I'm trying to listen to multiple TCP streams via tokio but I get an error:
use rybw_config::ListenerConfig;
use tokio::prelude::*;
use tokio::task::JoinHandle;
pub mod tcp;
use tcp::TCPListener;
pub struct Listener {
config: ListenerConfig,
tcp: Vec<tcp::TCPListener>,
}
impl Listener {
pub fn new(config: ListenerConfig) -> Listener {
let tcp: Vec<TCPListener> = config
.tcp
.clone()
.unwrap()
.iter()
.map(|x| TCPListener::new((*x).clone()))
.collect();
Listener {
tcp: tcp,
config: config.clone(),
}
}
pub async fn run(&self) {
let handles: Vec<JoinHandle<()>> = self.tcp.iter().map(|i| {
tokio::spawn(async {
i.run().await
})
}).collect();
futures::future::join_all(handles);
}
error: cannot infer an appropriate lifetime
--> rybw-listener/src/lib.rs:28:22
|
28 | pub async fn run(&self) {
| ^^^^^
| |
| data with this lifetime...
| ...is captured here...
29 | let handles: Vec<JoinHandle<()>> = self.tcp.iter().map(|i| {
30 | tokio::spawn(async {
| ------------ ...and required to be `'static` by this
Solved by myself.
rust closure captures the struct, not by individual fields. So we wrapper the TCPListener with std::sync::Arc and cloning it then used in spawn async {}
The type of i in your example is &tcp::TCPListener where the reference is still tied to self. However, tokio::spawn requires the spawned task to be 'static meaning it can't keep references to local variables.
The solution is to move owned values into the task. Common ways to do this are:
Use Clone to create a copy of the data needed by the task.
let handles: Vec<_> = self.tcp.iter().map(|listener| {
let listener = listener.clone();
// ^^^^^^^^ create a copy
tokio::spawn(async move {
// ^^^^ and move it into the async block
listener.run().await
})
}).collect();
Use shared ownership via Arc and Clone the handle needed by the task.
use std::sync::Arc;
struct Listener {
config: ListenerConfig,
tcp: Vec<Arc<tcp::TCPListener>>,
// ^^^ allow shared ownership
}
let handles: Vec<_> = self.tcp.iter().map(|listener| {
let listener = Arc::clone(listener);
// ^^^^^^^^^^ create a new handle to the same data
tokio::spawn(async move {
// ^^^^ and move it into the async block
listener.run().await
})
}).collect();
Provide ownership directly to the task. This won't really be an option in your example since &self is an immutable reference. But if you had an owned self or mutable reference and didn't need to keep your listeners after spawning tasks for them, you could use something like .into_iter() or .drain() on Vec to consume the listeners so their type is tcp::TCPListener (not a reference) and can easily be move-d into the task.
Related
I'm trying to create a reference to the current TCP connections. In this code, I'm trying to just print the current TCP connection's peer addresses in a loop and sleep for 10 seconds and the error I'm having is accessing the data between multiple threads.
I want to be able to manipulate a TCPStream from a different thread at any given point in time, to do things like shut down the TCPStream or get the peer address.
Can you please let me know what I'm doing wrong in a way that I can get a better understanding of how Arc and Mutex work?
use std::io::Read;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {
let server = Server {
connected_clients: Arc::new(Mutex::new(Vec::new()))
};
thread::spawn(move || {
let listener = TcpListener::bind("127.0.0.1:25565").unwrap();
// For each new connection start a new thread
for stream in listener.incoming() {
let stream = Arc::new(Mutex::new(stream.unwrap()));
let client = Client {
stream: stream.clone()
};
let cc = server.connected_clients.clone();
cc.lock().unwrap().push(client);
thread::spawn(move || {
// TODO: Add client to the connected_clients Vec
let mut buffer = [0; 1024];
loop {
stream.lock().unwrap().read(&mut buffer).unwrap();
println!("{}", String::from_utf8(Vec::from(&buffer[..])).unwrap().trim_end_matches(char::from(0)));
}
});
}
});
loop {
thread::sleep(Duration::from_secs(10));
// let vec = server.lock().unwrap().connected_clients.lock().unwrap().iter();
for client in server.connected_clients.lock().unwrap().iter() {
println!("{:?}", client.stream.lock().unwrap().peer_addr().unwrap())
}
}
}
#[derive(Debug)]
struct Server {
connected_clients: Arc<Mutex<Vec<Client>>>,
}
#[derive(Debug)]
struct Client {
stream: Arc<Mutex<TcpStream>>
}
ERROR:
error[E0382]: borrow of moved value: `server.connected_clients`
--> src\main.rs:40:23
|
12 | thread::spawn(move || {
| ------- value moved into closure here
...
22 | let cc = server.connected_clients.clone();
| ------------------------ variable moved due to use in closure
...
40 | for client in server.connected_clients.lock().unwrap().iter() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
|
= note: move occurs because `server.connected_clients` has type `Arc<Mutex<Vec<Client>>>`, which does not implement the `Copy` trait
= note: borrow occurs due to deref coercion to `Mutex<Vec<Client>>`
Just move the line let cc = server.connected_clients.clone(); before the first line thread::spawn(move || {.
The move keyword of the closure will now take ownership of cc, then the original server.connected_clients will stay available for the loop at the end of the program.
The idea behind Rc::clone() or Arc::clone() is exactly for the purpose of move closures: instead of moving the original ref-counted pointer to the resource into the closure, we move its clone and the original ref-counted pointer to the resource is still available in its original context.
I'm building a gRPC server using Rust and tonic and having some issues with a function that returns the stream. So far, the only examples I've seen conveniently create the tx and rx channels within the function - but this isn't a lot of help if you need to receive data from some other part of the application. I have the following code, but I'm getting an error.
Code
use std::sync::Arc;
use std::sync::Mutex;
use futures::{Stream, StreamExt};
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Sender, Receiver};
use tokio_stream::wrappers::ReceiverStream;
use tonic::transport::Server;
use tonic::{Request, Response, Status};use resourcemanager::{LineRequest, LineResponse, Position};
use resourcemanager::resource_manager_server::{ResourceManager, ResourceManagerServer};
pub mod resourcemanager {
tonic::include_proto!("resourcemanager");
}
#[derive(Debug)]
pub struct ResourceManagerService {
linear_rx: mpsc::Receiver<Position>,
linear_tx: mpsc::Sender<Position>
}
#[tonic::async_trait]
impl ResourceManager for ResourceManagerService {
async fn draw_line(&self, request: Request<LineRequest>) -> Result<Response<LineResponse>, Status> {
Ok(Response::new(LineResponse::default()))
}
type StreamLinearMotorMovementStream = ReceiverStream<Result<Position, Status>>;
async fn stream_linear_motor_movement(
&self,
request: Request<()>
) -> Result<Response<Self::StreamLinearMotorMovementStream>, Status> {
println!("Streaming motor movements");
let (tx, mut rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(received) = self.linear_rx.recv().await {
tx.send(Ok(received.clone())).await.unwrap();
}
});
Ok(Response::new(ReceiverStream::new(rx)))
}
}
fn main() {
println!("Hello, world!");
}
Error
error[E0759]: `self` has lifetime `'life0` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:30:10
|
30 | &self,
| ^^^^ this data with lifetime `'life0`...
...
36 | tokio::spawn(async move {
| ------------ ...is used and required to live as long as `'static` here
|
note: `'static` lifetime requirement introduced by this bound
--> /Users/xxxxxxxx/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.18.2/src/task/spawn.rs:127:28
|
127 | T: Future + Send + 'static,
| ^^^^^^^
This error is shown underneath &self in:
async fn stream_linear_motor_movement(
&self,
request: Request<()>
)
The error message basically says it all. Abbreviated:
async fn stream_linear_motor_movement(&self) {
let (tx, mut rx) = mpsc::channel(1);
tokio::spawn(async move {
while let Some(received) = self.linear_rx.recv().await {}
});
}
The fragment self.linear_rx.recv().await inside the newly spawned task forces the compiler to move self into that closure, so the closure can access self.linear_rx. However, as the new task could run forever, it requires its captured context to have a lifetime of 'static, while &self has a limited, possibly shorter than 'static, lifetime of life0 (whatever that turns out to be). What that means is that you can't access self (or anything derived from it) from within the newly spawned task, because there is no guarantee that it will be around while the task is executing.
What you can do is to move linear_rx in ResourceManagerService into an Arc, .clone() that Arc in stream_linear_motor_movement and move that clone into the closure. Depending on what you are trying to accomplish, you can also move linear_rx into an Option and .take() that Option in stream_linear_motor_movement, leaving None in its place. In both cases, you transfer an owned object into the newly spawned task, which has no lifetime shorter than 'static. Notice that Arc would allow one to call stream_linear_motor_movement many times, while Option would only allow one to call it exactly once (because linear_rx is moved away on the first call).
I have a tokio core whose main task is running a websocket (client). When I receive some messages from the server, I want to execute a new task that will update some data. Below is a minimal failing example:
use tokio_core::reactor::{Core, Handle};
use futures::future::Future;
use futures::future;
struct Client {
handle: Handle,
data: usize,
}
impl Client {
fn update_data(&mut self) {
// spawn a new task that updates the data
self.handle.spawn(future::ok(()).and_then(|x| {
self.data += 1; // error here
future::ok(())
}));
}
}
fn main() {
let mut runtime = Core::new().unwrap();
let mut client = Client {
handle: runtime.handle(),
data: 0,
};
let task = future::ok::<(), ()>(()).and_then(|_| {
// under some conditions (omitted), we update the data
client.update_data();
future::ok::<(), ()>(())
});
runtime.run(task).unwrap();
}
Which produces this error:
error[E0477]: the type `futures::future::and_then::AndThen<futures::future::result_::FutureResult<(), ()>, futures::future::result_::FutureResult<(), ()>, [closure#src/main.rs:13:51: 16:10 self:&mut &mut Client]>` does not fulfill the required lifetime
--> src/main.rs:13:21
|
13 | self.handle.spawn(future::ok(()).and_then(|x| {
| ^^^^^
|
= note: type must satisfy the static lifetime
The problem is that new tasks that are spawned through a handle need to be static. The same issue is described here. Sadly it is unclear to me how I can fix the issue. Even some attempts with and Arc and a Mutex (which really shouldn't be needed for a single-threaded application), I was unsuccessful.
Since developments occur rather quickly in the tokio landscape, I am wondering what the current best solution is. Do you have any suggestions?
edit
The solution by Peter Hall works for the example above. Sadly when I built the failing example I changed tokio reactor, thinking they would be similar. Using tokio::runtime::current_thread
use futures::future;
use futures::future::Future;
use futures::stream::Stream;
use std::cell::Cell;
use std::rc::Rc;
use tokio::runtime::current_thread::{Builder, Handle};
struct Client {
handle: Handle,
data: Rc<Cell<usize>>,
}
impl Client {
fn update_data(&mut self) {
// spawn a new task that updates the data
let mut data = Rc::clone(&self.data);
self.handle.spawn(future::ok(()).and_then(move |_x| {
data.set(data.get() + 1);
future::ok(())
}));
}
}
fn main() {
// let mut runtime = Core::new().unwrap();
let mut runtime = Builder::new().build().unwrap();
let mut client = Client {
handle: runtime.handle(),
data: Rc::new(Cell::new(1)),
};
let task = future::ok::<(), ()>(()).and_then(|_| {
// under some conditions (omitted), we update the data
client.update_data();
future::ok::<(), ()>(())
});
runtime.block_on(task).unwrap();
}
I obtain:
error[E0277]: `std::rc::Rc<std::cell::Cell<usize>>` cannot be sent between threads safely
--> src/main.rs:17:21
|
17 | self.handle.spawn(future::ok(()).and_then(move |_x| {
| ^^^^^ `std::rc::Rc<std::cell::Cell<usize>>` cannot be sent between threads safely
|
= help: within `futures::future::and_then::AndThen<futures::future::result_::FutureResult<(), ()>, futures::future::result_::FutureResult<(), ()>, [closure#src/main.rs:17:51: 20:10 data:std::rc::Rc<std::cell::Cell<usize>>]>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<usize>>`
= note: required because it appears within the type `[closure#src/main.rs:17:51: 20:10 data:std::rc::Rc<std::cell::Cell<usize>>]`
= note: required because it appears within the type `futures::future::chain::Chain<futures::future::result_::FutureResult<(), ()>, futures::future::result_::FutureResult<(), ()>, [closure#src/main.rs:17:51: 20:10 data:std::rc::Rc<std::cell::Cell<usize>>]>`
= note: required because it appears within the type `futures::future::and_then::AndThen<futures::future::result_::FutureResult<(), ()>, futures::future::result_::FutureResult<(), ()>, [closure#src/main.rs:17:51: 20:10 data:std::rc::Rc<std::cell::Cell<usize>>]>`
So it does seem like in this case I need an Arc and a Mutex even though the entire code is single-threaded?
In a single-threaded program, you don't need to use Arc; Rc is sufficient:
use std::{rc::Rc, cell::Cell};
struct Client {
handle: Handle,
data: Rc<Cell<usize>>,
}
impl Client {
fn update_data(&mut self) {
let data = Rc::clone(&self.data);
self.handle.spawn(future::ok(()).and_then(move |_x| {
data.set(data.get() + 1);
future::ok(())
}));
}
}
The point is that you no longer have to worry about the lifetime because each clone of the Rc acts as if it owns the data, rather than accessing it via a reference to self. The inner Cell (or RefCell for non-Copy types) is needed because the Rc can't be dereferenced mutably, since it has been cloned.
The spawn method of tokio::runtime::current_thread::Handle requires that the future is Send, which is what is causing the problem in the update to your question. There is an explanation (of sorts) for why this is the case in this Tokio Github issue.
You can use tokio::runtime::current_thread::spawn instead of the method of Handle, which will always run the future in the current thread, and does not require that the future is Send. You can replace self.handle.spawn in the code above and it will work just fine.
If you need to use the method on Handle then you will also need to resort to Arc and Mutex (or RwLock) in order to satisfy the Send requirement:
use std::sync::{Mutex, Arc};
struct Client {
handle: Handle,
data: Arc<Mutex<usize>>,
}
impl Client {
fn update_data(&mut self) {
let data = Arc::clone(&self.data);
self.handle.spawn(future::ok(()).and_then(move |_x| {
*data.lock().unwrap() += 1;
future::ok(())
}));
}
}
If your data is really a usize, you could also use AtomicUsize instead of Mutex<usize>, but I personally find it just as unwieldy to work with.
I am trying to fire up a new thread using some heap data in Rust and I am getting a bunch of errors that stem from the need of the data to have 'static lifetime. I've worked my way backwards up my program but hit a problem.
use std::sync::Arc;
use std::thread;
struct ThreadData {
vector_of_strings: Vec<String>,
terms: Vec<&'static str>,
quotient: usize,
}
fn perform_search(slice: &[String], terms: &[&str]) {
/* ... */
}
fn threaded_search(td_arc: &Arc<ThreadData>) {
let no_of_lines = td_arc.vector_of_strings.len();
let new_tda1 = td_arc.clone();
let strings_as_slice1 = new_tda1.vector_of_strings.as_slice();
thread::spawn(move || {
perform_search(&strings_as_slice1[0..td_arc.quotient], &new_tda1.terms);
});
}
fn main() {
let td = ThreadData {
vector_of_strings: Vec::new(),
terms: Vec::new(),
quotient: 0,
};
let td_arc = Arc::new(td);
threaded_search(&td_arc);
}
Error:
error[E0621]: explicit lifetime required in the type of `td_arc`
--> src/main.rs:20:5
|
14 | fn threaded_search(td_arc: &Arc<ThreadData>) {
| ---------------- help: add explicit lifetime `'static` to the type of `td_arc`: `&'static std::sync::Arc<ThreadData>`
...
20 | thread::spawn(move || {
| ^^^^^^^^^^^^^ lifetime `'static` required
The error about 'static is because the new thread created within thread::spawn may outlive the invocation of threaded_search during which the thread is initially created, which means the thread must not be permitted to use any local variables from threaded_search with a lifetime shorter than 'static.
In your code the new thread is referring to strings_as_slice1 and td_arc.
Generally with thread::spawn and Arc you will want to move ownership of one reference count into the thread and have the thread access whatever it needs through that reference counted pointer rather than from the enclosing short-lived scope directly.
fn threaded_search(td_arc: &Arc<ThreadData>) {
// Increment reference count that we can move into the new thread.
let td_arc = td_arc.clone();
thread::spawn(move || {
perform_search(&td_arc.vector_of_strings[0..td_arc.quotient], &td_arc.terms);
});
}
Still struggling with the Rust mind shift, now I have this use case - one configuration for a multi-threaded TcpListener:
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
use std::thread;
fn main() {
serve("127.0.0.1:3333", Configuration { do_something: true });
}
//#[derive(Copy, Clone)]
pub struct Configuration {
pub do_something: bool,
}
pub fn serve<A: ToSocketAddrs>(addr: A, conf: Configuration) {
let listener = TcpListener::bind(addr).expect("bind failed");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
thread::spawn(move || {
handle_client(stream, &conf);
});
}
Err(e) => {
println!("Connection failed: {}", e);
}
}
}
}
fn handle_client(stream: TcpStream, conf: &Configuration) {
if conf.do_something {
//stream....
}
}
I'm happy that the TcpStream is consumed by handle_client, that's it's purpose, but why does Configuration have to be copied for each thread? I'd like to have just one copy and share an immutable reference with all threads. Is that possible? Or perhaps I'm missing the point.
Why do I need the Copy and Clone traits if I'm passing Configuration by reference? This confused me a good deal:
error[E0382]: capture of moved value: `conf`
--> src/main.rs:19:64
|
19 | thread::spawn(move || { handle_client(stream, &conf); });
| ------- ^^^^ value captured here after move
| |
| value moved (into closure) here
|
= note: move occurs because `conf` has type `Configuration`, which does not implement the `Copy` trait
Implementing Copy (Clone is incidental here) only fixes the problem because implementing it allows the compiler to implicitly duplicate the Configuration struct, passing a copied value into the thread.
It needs to pass the variable by value because you told the compiler to move all used values into the closure:
thread::spawn(move || {
// ^^^^ HERE
handle_client(stream, &conf);
});
The entire purpose of the move keyword is to tell the compiler "no, don't try to infer how variables are used inside this closure, just move everything in".
When you move &conf, the compiler says "OK, I'll move conf into the closure then take a reference to it".
In your case, you can just remove the move keyword:
thread::spawn(|| {
handle_client(stream, &conf);
});
If you really need to be able to use the move keyword and pass in a reference, you need to move in a reference:
let conf = &conf;
thread::spawn(move || {
handle_client(stream, conf);
});
This still doesn't allow your code to compile because there's no guarantee that the reference outlives the thread. That's discussed thoroughly in Passing a reference to a stack variable to a scoped thread.