Using trait methods in threads - multithreading

Basically, I'm making a program that's listening to a bunch of ports and that handles incoming packets in different ways. I decide to bundle this code into a Trait:
use std::old_io::{TcpStream, TcpListener, Listener, Acceptor, EndOfFile, IoResult};
use std::thread::Thread;
trait Server {
fn new(port: u16) -> Self;
fn hostname(&self) -> &String;
fn initialize(&self) {
let acceptor = TcpListener::bind(self.hostname().as_slice()).listen().unwrap();
Thread::spawn(move|| {
let mut acceptor = acceptor;
for incoming_stream in acceptor.incoming() {
match incoming_stream {
Ok(stream) => {
self.handle_client(stream);
},
Err(ref e) if e.kind == EndOfFile => break,
Err(e) => panic!("Unexpected error: {}", e),
}
}
});
}
fn handle_client(&self, stream: TcpStream) -> ();
}
pub struct InternodeServer {
hostname: String,
}
impl Server for InternodeServer {
fn new(port: u16) -> InternodeServer {
let hostname = format!("127.0.0.1:{}", port);
InternodeServer {
hostname: hostname,
}
}
fn hostname(&self) -> &String {
&self.hostname
}
fn handle_client(&self, stream: TcpStream) {
println!("Received connection");
let mut stream = stream;
let response = b"Hello\r\n";
let _ = stream.write_all(response);
let _ = stream.close_write();
}
}
fn main() {
let test_server = <InternodeServer as Server>::new(9337);
test_server.initialize();
}
However, this code won't work because you can't send Self. This is the error I receive:
test.rs:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `Self` [E0277]
test.rs:11 Thread::spawn(move|| {
^~~~~~~~~~~~~
test.rs:11:9: 11:22 note: `Self` cannot be sent between threads safely
test.rs:11 Thread::spawn(move|| {
^~~~~~~~~~~~~
So I also tried making handle_client a static method to avoid self. To do this, I simply changed handle_client to:
fn handle_client(stream: TcpStream)
And referenced it by doing:
Server::handle_client(stream);
However, I can't reference InternodeServer's static methods from Server's initialize method. When compiling, I get an error like:
test.rs:16:25: 16:46 error: type annotations required: cannot resolve `_ : Server` [E0283]
test.rs:16 Server::handle_client(stream);
^~~~~~~~~~~~~~~~~~~~~
test.rs:16:25: 16:46 note: required by `Server::handle_client`
test.rs:16 Server::handle_client(stream);
Is there any way around this?

Here's a smaller reproduction of the error:
use std::thread::Thread;
trait Server {
fn initialize(&self) {
Thread::spawn(move || self.handle_client());
}
fn handle_client(&self);
}
fn main() {}
The problem is that the argument passed to Thread::spawn must be Send. You are trying to move self into the closure, but your trait doesn't guarantee Send, so the closure can't be Send.
We can attempt to go down that path with trait Server: Send, but then we get "cannot infer an appropriate lifetime" errors because Send also requires 'static (for now). Also, it seems very strange to move yourself into a closure.
Really, I think you want to split up your code. Move handle_client into a separate trait and then ensure that implementations of that trait are Send:
use std::thread::Thread;
trait Server {
fn initialize<D>(&self, driver: D)
where D: Driver + Send
{
Thread::spawn(move || driver.handle_client());
}
}
trait Driver {
fn handle_client(&self);
}
fn main() {}

I don't think that rust will allow you to invoke object methods directly from other thread because "move" closures cannot borrow anything, only move.
So you have to use some kind of inter-thread communication tool, for example, channels:
use std::thread::Thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use std::net::{TcpStream, TcpListener};
use std::io::{ErrorKind, Write};
trait Server {
fn new(port: u16) -> Self;
fn hostname(&self) -> &String;
fn initialize(&mut self, _detached: bool) {
let acceptor = TcpListener::bind(self.hostname().as_slice()).unwrap();
let server_tx = self.make_pipe();
Thread::spawn(move|| {
for incoming_stream in acceptor.incoming() {
match incoming_stream {
Ok(stream) => server_tx.send(Arc::new(Mutex::new(stream))).unwrap(),
Err(ref e) if e.kind() == ErrorKind::NotConnected => break,
Err(e) => panic!("Unexpected error: {}", e),
}
}
});
}
fn handle_client(&self, stream: Arc<Mutex<TcpStream>>);
fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>>;
fn run(&self);
}
pub struct InternodeServer {
hostname: String,
client_rx: Option<Receiver<Arc<Mutex<TcpStream>>>>,
}
impl Server for InternodeServer {
fn new(port: u16) -> InternodeServer {
let hostname = format!("127.0.0.1:{}", port);
InternodeServer {
hostname: hostname,
client_rx: None,
}
}
fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>> {
let (server_tx, client_rx) = channel();
self.client_rx = Some(client_rx);
server_tx
}
fn hostname(&self) -> &String {
&self.hostname
}
fn handle_client(&self, stream_arc: Arc<Mutex<TcpStream>>) {
println!("Received connection");
let mut stream = stream_arc.lock().unwrap();
let response = b"Hello\r\n";
let _ = stream.write_all(response);
let _ = drop(stream);
}
fn run(&self) {
loop {
match self.client_rx.as_ref().unwrap().recv() {
Ok(stream) => self.handle_client(stream),
Err(RecvError) => break,
}
}
}
}
fn main() {
let mut s = <InternodeServer as Server>::new(10101);
s.initialize(false);
s.run();
}

Related

Cannot borrow data in an `Arc` as mutable

I don't know what to do next. It looks like I misunderstand something, or maybe I have not learned some critical topic.
use std::sync::Arc;
use reqwest::{Error, Response}; // 0.11.4
use tokio::sync::mpsc::{self, Receiver, Sender}; // 1.9.0
pub struct Task {
pub id: u32,
pub url: String,
}
pub enum Message {
Failure(Task, Error),
Success(Task, Response),
}
struct State {
client: reqwest::Client,
res_tx: Sender<Message>,
res_rx: Receiver<Message>,
}
pub struct Proxy {
state: Arc<State>,
max_rps: u16,
max_pending: u16,
id: u32,
parent_tx: Sender<String>,
}
async fn send_msg<T>(tx: &Sender<T>, msg: T) {
match tx.send(msg).await {
Err(error) => {
eprintln!("{}", error)
}
_ => (),
};
}
impl Proxy {
// Starts loop for input channel
async fn start_chin(&mut self) -> Sender<Task> {
let (chin_tx, mut chin_rx) = mpsc::channel::<Task>(self.max_pending as usize + 1 as usize);
let state_outer = self.state.clone();
tokio::spawn(async move {
loop {
match chin_rx.recv().await {
Some(task) => {
let res_tx = state_outer.res_tx.clone();
let state = state_outer.clone();
tokio::spawn(async move {
match state.client.get(&task.url).send().await {
Ok(res) => send_msg(&res_tx, Message::Success(task, res)).await,
Err(err) => send_msg(&res_tx, Message::Failure(task, err)).await,
}
});
}
None => (),
}
}
});
chin_tx
}
async fn start_chres(&self) {
let state = self.state.clone();
tokio::spawn(async move {
loop {
match state.res_rx.recv().await { // LINE PRODUCES ERROR
Some(task) => {}
None => (),
}
}
});
}
}
impl Proxy {
pub fn new(
id: u32,
parent_tx: Sender<String>,
proxy_addr: &str,
max_rps: u16,
max_pending: u16,
) -> Result<Self, Error> {
let client = reqwest::Client::builder();
if proxy_addr != "none" {
client = client.proxy(reqwest::Proxy::all(proxy_addr)?)
}
let (res_tx, res_rx) = mpsc::channel::<Message>(max_pending as usize + 1 as usize); // TODO: check size
Ok(Proxy {
id,
state: Arc::new(State {
client: client.build()?,
res_tx,
res_rx,
}),
max_rps,
max_pending,
parent_tx,
})
}
}
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/lib.rs:69:23
|
69 | match state.res_rx.recv().await {
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<State>`
use std::sync::Arc;
struct Something {
size: usize
}
impl Something {
fn increase(&mut self) {
self.size = self.size + 1;
}
}
fn main() {
let something = Something{size: 1};
let arc = Arc::new(something);
arc.increase();
}
gives
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/main.rs:16:5
|
16 | arc.increase();
| ^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<Something>`
error: aborting due to previous error; 1 warning emitted
because it tries to borrow arc as mutable. For it to happen, DerefMut would have to be implemented for Arc but it's not because Arc is not meant to be mutable.
Wraping your object in a Mutex works:
use std::sync::{Arc, Mutex};
struct Something {
size: usize
}
impl Something {
fn increase(&mut self) {
self.size = self.size + 1;
}
}
fn main() {
let something = Something{size: 1};
let arc = Arc::new(Mutex::new(something));
arc.lock().unwrap().increase();
}
Now it can be shared and can be increased.
Lucas Zanella's answer and Shepmaster's comments helped alot to refactor and simplify code. I've desided to pass ownership inside Proxy::new() function instead of using shared reference. The code became more readable, and I've avoided shared reference for mutable tokio::sync::mpsc::Receiver. Perhaps the question turned out to be too unstructured, but I came to a new approach thanks to the community. Refactored code is listed below.
use reqwest::{Client, Error, Response};
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Sender, Receiver};
pub struct Task {
pub id: u32,
pub url: String,
}
pub enum Message{
Failure(Task, Error),
Success(Task, Response),
}
pub struct Proxy{
id: u32,
max_rps: u16,
max_pending: u16,
in_tx: Sender<Task>,
}
async fn send_msg<T>(tx: &Sender<T>, msg: T){
match tx.send(msg).await {
Err(error) => { eprintln!("{}", error) },
_ => (),
};
}
async fn start_loop_in(client: Client, mut in_rx: Receiver<Task>, res_tx: Sender<Message>){
loop {
if let Some(task) = in_rx.recv().await {
let client_clone = client.clone();
let res_tx_clone = res_tx.clone();
tokio::spawn(async move {
println!("SENDING: {}", &task.url); // TODO: DELETE DEBUG
match client_clone.get(&task.url).send().await {
Ok(res) => send_msg(&res_tx_clone, Message::Success(task, res)).await,
Err(err) => send_msg(&res_tx_clone, Message::Failure(task, err)).await,
}
});
}
}
}
async fn start_loop_res(mut res_rx: Receiver<Message>, out_tx: Sender<String>){
loop {
if let Some(message) = res_rx.recv().await {
match message {
Message::Success(task, res) => {
send_msg(
&out_tx,
format!("{:#?}", res.text().await.unwrap()) // TODO: change in release!
).await;
},
Message::Failure(task, err) => {
send_msg(&out_tx, err.to_string()).await;
},
}
}
}
}
impl Proxy{
pub fn new(id: u32, parent_tx: Sender<String>, proxy_addr: &str, max_rps: u16, max_pending: u16) -> Result<Self, Error> {
let mut client = Client::builder();
if proxy_addr != "none" { client = client.proxy(reqwest::Proxy::all(proxy_addr)?) }
let (res_tx, res_rx) = mpsc::channel::<Message>(max_pending as usize + 1 as usize); // TODO: check size
let client = client.build()?;
let (in_tx, in_rx) = mpsc::channel::<Task>(max_pending as usize + 1 as usize);
let res_tx_clone = res_tx.clone();
tokio::spawn(async move { start_loop_in(client, in_rx, res_tx_clone).await });
tokio::spawn(async move { start_loop_res(res_rx, parent_tx).await });
Ok(Proxy{
id,
max_rps,
max_pending,
in_tx,
})
}
pub fn get_in_tx(&self) -> Sender<Task> {
self.in_tx.clone()
}
}

How to send generic T to another thread?

How to send generic T?
I try to send a generic T to another thread but I'm getting:
error[E0308]: mismatched types
--> src/main.rs:23:22
|
23 | t1.merge(Element(vec![3]));
| ^^^^^^^^^^^^^^^^ expected associated type, found struct `Element`
|
= note: expected associated type `<T as Join>::Item`
found struct `Element`
= help: consider constraining the associated type `<T as Join>::Item` to `Element`
Full code:
trait Join {
type Item;
fn merge(&mut self, other: Self::Item);
}
#[derive(Debug, Default)]
struct Element(Vec<u8>);
impl Join for Element {
type Item = Element;
fn merge(&mut self, mut other: Self::Item) {
self.0.append(&mut other.0);
}
}
fn work<T>()
where
T: Default + Join + Send + Sync + 'static,
{
let (sender, receiver) = std::sync::mpsc::channel::<(T)>();
std::thread::spawn(move || {
while let (mut t1) = receiver.recv().unwrap() {
t1.merge(Element(vec![3]));
}
});
loop {
let mut t1 = T::default();
sender.send(t1);
std::thread::sleep(std::time::Duration::from_secs(5));
}
}
fn main() {
// works!
let mut e = Element(vec![1]);
e.merge(Element(vec![2]));
// bad!
work::<Element>();
}
Playground link
When you use generics you let the caller decide which types must be used by your generic function.
This line in your example t1.merge(Element(vec![3])); is invalid because it assumes T = Element but the caller can chose from infinitely many possible types of T where T != Element which is why the compiler is complaining.
To make your function fully generic you have to do something like add a Default bound to <T as Join>::Item in the function signature and then change the offending line to t1.merge(<T as Join>::Item::default());.
Updated working commented example:
use std::fmt::Debug;
trait Join {
type Item;
fn merge(&mut self, other: Self::Item);
}
#[derive(Debug)]
struct Element(Vec<u8>);
// updated Default impl so we can observe merges
impl Default for Element {
fn default() -> Self {
Element(vec![1])
}
}
impl Join for Element {
type Item = Element;
fn merge(&mut self, mut other: Self::Item) {
self.0.append(&mut other.0);
}
}
fn work<T>() -> Result<(), Box<dyn std::error::Error>>
where
T: Default + Join + Send + Sync + Debug + 'static,
<T as Join>::Item: Default, // added Default bound here
{
let (sender, receiver) = std::sync::mpsc::channel::<T>();
std::thread::spawn(move || {
while let Ok(mut t1) = receiver.recv() {
// changed this to use Default impl
t1.merge(<T as Join>::Item::default());
// prints "Element([1, 1])" three times
println!("{:?}", t1);
}
});
let mut iterations = 3;
loop {
let t1 = T::default();
sender.send(t1)?;
std::thread::sleep(std::time::Duration::from_millis(100));
iterations -= 1;
if iterations == 0 {
break;
}
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// works!
let mut e = Element(vec![1]);
e.merge(Element(vec![2]));
// now also works!
work::<Element>()?;
Ok(())
}
playground

Sending a closure (which returns a struct with a trait) to a thread leads to sized error

I'm trying to send a closure which will generate a structure to a thread, however when I try to do it I get a Sized error. I understand the error (the size is indeed not known at compile time), however adding Boxes and other such tricks does not seem to solve it.
I've tried to look into how to implement the Sized trait, however it seems to be quite special and honestly above my understanding.
I've written a minimal reproducible example:
use std::thread;
trait DataProcess {
fn start(&self);
fn run(&self);
fn stop(&self);
}
struct SomeDP {
name: String,
}
impl DataProcess for SomeDP {
fn start(&self) {
println!("Started");
}
fn run(&self) {
println!("Running");
}
fn stop(&self) {
println!("Stopped");
}
}
fn thread_maker(builder: Box<dyn Fn() -> (dyn DataProcess + Send)>) {
let thread_builder = thread::Builder::new();
let handle = thread_builder.spawn(move || {
let dp = builder();
dp.start();
});
}
fn main() {
let dp_builder = || SomeDP {
name: "nice".to_string(),
};
thread_maker(Box::new(dp_builder));
}
Which you can also find on the playground here
This works
use std::thread;
trait DataProcess{
fn start(&self);
fn run(&self);
fn stop(&self);
}
struct SomeDP{
name: String
}
impl DataProcess for SomeDP{
fn start(&self){println!("Started");}
fn run(&self){println!("Running");}
fn stop(&self){println!("Stopped");}
}
fn thread_maker<F>(builder: F)
where
F: Fn() -> Box<dyn DataProcess>,
F: Send + 'static {
let thread_builder = thread::Builder::new();
let handle = thread_builder.spawn(
move ||{
let dp = builder();
dp.start();
}
);
}
fn main(){
let dp_builder = || -> Box<dyn DataProcess> {
Box::new(SomeDP{name: "nice".to_string()})
};
thread_maker(dp_builder);
}

Initializing a FnMut member variable with a static Fn function

Problem Description
I have a Config struct that can store a FnMut callback function. The catch is: not all of my configurations require a callback function, so I would like to make adding a callback function optional. This requires the member variable to be initialized with a default function that will get used if no callback is set.
Existing Code
struct Config<'a>{
callback: &'a mut dyn (FnMut(&str))
}
fn default_fn(msg: &str){
println!("default_fn({})", msg);
}
impl<'a> Config<'a> {
pub fn new() -> Config<'a> {
Config{
callback: &default_fn // ERROR: types differ in mutability
}
}
pub fn set_callback(mut self, callback_fn: &'a mut dyn (FnMut(&str))) -> Config<'a> {
self.callback = callback_fn;
self
}
}
fn main() {
// Our FnMut callback
let mut msg_log: Vec<String> = vec![];
let mut callback_fn = |msg: &str| {
msg_log.push(msg.to_string());
};
{
let mut config = Config::new();
(config.callback)("Hello World!");
config = config.set_callback(&mut callback_fn);
(config.callback)("Hello World!");
}
// Demonstration that the callback actually works
println!("{:?}", msg_log);
}
error[E0308]: mismatched types
--> src/main.rs:13:23
|
13 | callback: &default_fn // ERROR: types differ in mutability
| ^^^^^^^^^^^ types differ in mutability
|
= note: expected type `&mut dyn for<'r> std::ops::FnMut(&'r str)`
found type `&for<'r> fn(&'r str) {default_fn}`
Does someone have any suggestions on how to solve that problem?
Things I already tried, without any success:
Initializing it with a closure: callback: &|_: &str|{}
Using a member function instead of a global function
Creating a mutable reference: callback: &mut default_fn
(causes: cannot return value referencing temporary value)
I'm running out of ideas, any help is appreciated. Even if the answer is that what I am trying to do is impossible for reasons I didn't realize yet.
You should really box the trait object function. That makes the whole code much easier to use:
struct Config<'a>{
callback: Box<dyn FnMut(&str) + 'a>,
}
fn default_fn(msg: &str){
println!("default_fn({})", msg);
}
impl<'a> Config<'a> {
pub fn new() -> Config<'a> {
Config{
callback: Box::new(default_fn)
}
}
pub fn set_callback(self, callback: &'a mut dyn (FnMut(&str))) -> Config<'a> {
Config {
callback: Box::new(callback),
..self
}
}
}
fn main() {
// Our FnMut callback
let mut msg_log = vec![];
let mut callback_fn = |msg: &str| {
msg_log.push(msg.to_string());
};
{
let mut config = Config::new();
(config.callback)("Hello World!");
config = config.set_callback(&mut callback_fn);
(config.callback)("Hello World!");
}
// Demonstration that the callback actually works
println!("{:?}", msg_log);
}
Note that it is difficult to use callbacks in idiomatic Rust. I would even say that they aren't idiomatic at all. You should use a channel, something like that:
use std::sync::mpsc::{channel, Sender, SendError};
struct Config {
sender: Sender<String>,
}
impl Config {
pub fn new(sender: Sender<String>) -> Config {
Config{
sender
}
}
pub fn send(&self, message: String) -> Result<(), SendError<String>> {
self.sender.send(message)
}
}
fn main() {
let (sender, receiver) = channel();
let config = Config::new(sender);
config.send("Hello world!".into()).unwrap();
println!("{:?}", receiver.recv().unwrap());
}
Just wanted to share the solution I found:
Single-threaded, callback-based.
While in my opinion this one really answers the question I had, I think you guys are still right about the problems I might encounter in the future with this programming style. I will definitely reconsider your advice about using channels.
struct Config<'a>{
callback: Option<&'a mut dyn (FnMut(&str))>
}
impl<'a> Config<'a> {
pub fn new() -> Config<'a> {
Config{
callback: None
}
}
pub fn set_callback(mut self, callback_fn: &'a mut dyn (FnMut(&str))) -> Config<'a> {
self.callback = Some(callback_fn);
self
}
pub fn run_callback(&mut self, msg: &str){
if let Some(callback) = &mut self.callback{
callback(msg);
} else {
// Default code
println!("default_fn({})", msg);
}
}
}
fn main() {
// Our FnMut callback
let mut msg_log: Vec<String> = vec![];
let mut callback_fn = |msg: &str| {
msg_log.push(msg.to_string());
};
let mut config = Config::new();
config.run_callback("Hello World!");
config = config.set_callback(&mut callback_fn);
config.run_callback("Hello World!");
// Demonstration that the callback actually works
println!("{:?}", msg_log);
}

Is it possible to call a FnOnce from a Fn without a Mutex?

Fn can be sent via a channel, but FnOnce cannot yet on stable. In order to send a FnOnce through a channel it is possible to wrap it in a Fn, as shown below.
However, this requires a Mutex, which introduces an annoying overhead when scaling to very high throughput (i.e. tangibly, when you do this a lot, it's slow).
Is there some other concurrency primitive I could use here that would be less heavyweight? Perhaps with std::sync::atomic? Can this be done without a lock?
I have no interest in using nightly features or crates that rely on undefined behavior.
use std::thread;
use std::sync::Mutex;
use std::sync::mpsc;
struct RawFunc {
data: Box<Fn() + Send + 'static>,
}
impl RawFunc {
fn new<T>(inner: T) -> RawFunc
where
T: FnOnce() + Send + 'static,
{
let inner_lock = Mutex::new(Some(inner));
return RawFunc {
data: Box::new(move || match inner_lock.lock() {
Ok(mut i) => (i.take().unwrap())(),
Err(_) => {}
}),
};
}
fn invoke(self) {
(self.data)()
}
}
fn main() {
// Local
let x = RawFunc::new(move || {
println!("Hello world");
});
x.invoke();
// Via channel
let (sx, rx) = mpsc::channel::<RawFunc>();
sx.send(RawFunc::new(move || {
println!("Hello world 2");
})).unwrap();
let output = rx.recv().unwrap();
output.invoke();
// In a thread
let guard = thread::spawn(move || {
let output = rx.recv().unwrap();
output.invoke();
});
sx.send(RawFunc::new(move || {
println!("Hello world 3!");
})).unwrap();
guard.join().unwrap();
// Passing arbitrary data to a thread
let (sx, rx) = mpsc::channel::<RawFunc>();
let guard = thread::spawn(move || {
let output = rx.recv().unwrap();
output.invoke();
});
let bar = RawFunc::new(move || {
println!("Moved func!");
});
let foo = String::from("Hello World 4");
sx.send(RawFunc::new(move || {
println!("Some moved data: {:?}", foo);
bar.invoke();
})).unwrap();
guard.join().unwrap();
}
playground
The author of the cursive crate had exactly the same problem and solved it with their own trait.
/// Asynchronous callback function trait.
///
/// Every `FnOnce(&mut Cursive) -> () + Send` automatically
/// implements this.
///
/// This is a workaround only because `Box<FnOnce()>` is not
/// working and `FnBox` is unstable.
pub trait CbFunc: Send {
/// Calls the function.
fn call_box(self: Box<Self>, &mut Cursive);
}
impl<F: FnOnce(&mut Cursive) -> () + Send> CbFunc for F {
fn call_box(self: Box<Self>, siv: &mut Cursive) {
(*self)(siv)
}
}
source
Here is the PR, where the code was introduced.

Resources