How do I call a function every X seconds with a parameter that doesn't implement Copy? - multithreading

I'm creating a basic Minecraft server in Rust. As soon as a player logs in to my server, I need to send a KeepAlive packet every 20 seconds to ensure the client is still connected.
I thought this would be solved by spawning a new thread that sends the packet after sleeping 20 seconds. (line 35). Unfortunately, the Server type doesn't implement Copy.
Error
error[E0382]: borrow of moved value: `server`
--> src/main.rs:22:9
|
20 | let mut server = Server::from_tcpstream(stream).unwrap();
| ---------- move occurs because `server` has type `ozelot::server::Server`, which does not implement the `Copy` trait
21 | 'listenloop: loop {
22 | server.update_inbuf().unwrap();
| ^^^^^^ value borrowed here after move
...
35 | thread::spawn(move || {
| ------- value moved into closure here, in previous iteration of loop
Code:
use std::thread;
use std::io::Read;
use std::fs::File;
use std::time::Duration;
use std::io::BufReader;
use ozelot::{Server, clientbound, ClientState, utils, read};
use ozelot::serverbound::ServerboundPacket;
use std::net::{TcpListener, TcpStream};
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("0.0.0.0:25565")?;
for stream in listener.incoming() {
handle_client(stream?);
}
Ok(())
}
fn handle_client(stream: TcpStream) {
let mut server = Server::from_tcpstream(stream).unwrap();
'listenloop: loop {
server.update_inbuf().unwrap();
let packets = server.read_packet().unwrap_or_default();
'packetloop: for packet in packets {
match packet {
//...
ServerboundPacket::LoginStart(ref p) => {
//...
//send keep_alive every 20 seconds
thread::spawn(move || {
thread::sleep(Duration::from_secs(20));
send_keep_alive(server)
});
fn send_keep_alive(mut server: Server) {
server.send(clientbound::KeepAlive::new(728)).unwrap();
}
//...
},
//...
_ => {},
}
}
thread::sleep(Duration::from_millis(50));
}
}

Notice how most of the functions in ozelot::Server take &mut self as a parameter. This means that they are called on a mutable reference to a ozelot::Server.
From Rust docs:
you can only have one mutable reference to a particular piece of data in a particular scope
The issue is - how can we share ozelot::Server between the main thread and the new thread?
A lot of things in std::sync module solve exactly these kinds of problems. In your case, you want read access from the main thread and write access from the thread calling send_keep_alive. This calls for Mutex - exclusive read/write access at a time, and
Wrap the server in an Arc<Mutex>:
use std::sync::{Arc, Mutex};
// --snip--
fn handle_client(stream: TcpStream) {
let mut server = Server::from_tcpstream(stream).unwrap();
let mut server = Arc::new(Mutex::new(server));
Move a clone of Arc into the thread, and lock the Mutex to gain access:
let server = Arc::clone(server);
thread::spawn(move || {
thread::sleep(Duration::from_secs(20));
send_keep_alive(&mut server)
});
And make send_keep_alive receive server by mutable reference:
fn send_keep_alive(server: &mut Arc<Mutex<Server>>) {
loop {
let mut server = server.lock().unwrap();
server.send(clientbound::KeepAlive::new(728)).unwrap();
}
}

Related

Actix: what's the right way to move shared data into multiple threads?

I have a config Struct that I'm sharing across my actix app like so:
pub fn run(addr: &str, pg_pool: PgPool, config: Settings) -> Result<Server, std::io::Error> {
let pool = web::Data::new(pg_pool);
let arc_config = web::Data::new(Arc::new(config)); // <---
let server = HttpServer::new(move || {
App::new()
.service(exhaust)
.app_data(pool.clone())
.app_data(arc_config.clone()) // <---
})
.bind(addr)?
.run();
I then have a handler that is trying to spawn multiple threads and pass that config struct into each:
#[get("/exhaust")]
pub async fn exhaust(pool: web::Data<PgPool>, config: web::Data<Arc<Settings>>) -> impl Responder {
for _ in 1..16 {
let handle = thread::spawn(move || {
let inner_config = Arc::clone(&config);
get_single_tweet(inner_config.as_ref().deref(), "1401287393228038149");
});
}
HttpResponse::Ok()
}
My thinking was that because config is already wrapped in an Arc() I should be able to just Arc::clone() it inside of each thread and then deref into the underlying variable.
But I'm getting this error:
error[E0382]: use of moved value: `config`
--> src/twitter/routes/pull.rs:63:36
|
58 | pub async fn exhaust(pool: web::Data<PgPool>, config: web::Data<Arc<Settings>>) -> impl Responder {
| ------ move occurs because `config` has type `actix_web::web::Data<Arc<Settings>>`, which does not implement the `Copy` trait
...
63 | let handle = thread::spawn(move || {
| ^^^^^^^ value moved into closure here, in previous iteration of loop
64 | let inner_config = Arc::clone(&config);
| ------ use occurs due to use in closure
I'm struggling to understand why this fails. If the config is inside an Arc, then why does the compiler think I'm trying to move it instead of incrementing the reference count?
I've also tried a number of other approaches, all unsuccessful:
Removing the move in front of the closure - compiler complains the borrowed value doesn't live long enough
Dereferencing config and wrapping it in a fresh Arc() - similar error as original
What's the right way to do this?
You need to clone it before it's moved. Otherwise your first iteration will necessarily need to take it (since there is no guarantee config will still exist to be cloned when the task runs). Then you get the error you see for the second iteration, since it too necessarily needs to move config; that's what it means by "value moved into closure here, in previous iteration of loop".
#[get("/exhaust")]
pub async fn exhaust(pool: web::Data<PgPool>, config: web::Data<Arc<Settings>>) -> impl Responder {
for _ in 1..16 {
let handle = thread::spawn({
// Clone this here, so the closure gets its very own to move-capture.
let inner_config = config.get_ref().clone();
move || {
get_single_tweet(inner_config.as_ref().deref(), "1401287393228038149");
});
}
}
HttpResponse::Ok()
}
Note that web::Data itself is already just a wrapper around Arc, so you have some redundancy with the nested Arc. You may just want:
#[get("/exhaust")]
pub async fn exhaust(pool: web::Data<PgPool>, config: web::Data<Settings>) -> impl Responder {
for _ in 1..16 {
let handle = thread::spawn({
let inner_config = config.clone();
move || {
get_single_tweet(inner_config.as_ref().deref(), "1401287393228038149");
});
}
}
HttpResponse::Ok()
}

Wait for backend thread to finish after application.run in Rust

I want to wait for a backend thread (Like this but in my case the backend manages a database which I want to close properly before the application actually exits) to finish (e.g. join it) after application.run() has finished.
My actual non working main.rs (the closure needs to be non-mut)
the thread to wait for
use gio::prelude::*;
use gtk::prelude::*;
use gtk::{ApplicationWindow, Label};
use std::env::args;
use std::thread;
fn main() {
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.communication_thread"),
Default::default(),
)
.expect("Initialization failed...");
let (thr, mut receiver) = start_communication_thread();
application.connect_activate(move |application| {
build_ui(application, receiver.take().unwrap())
});
application.run(&args().collect::<Vec<_>>());
thr.join();
}
fn build_ui(application: &gtk::Application, receiver: glib::Receiver<String>) {
let window = ApplicationWindow::new(application);
let label = Label::new(None);
window.add(&label);
spawn_local_handler(label, receiver);
window.show_all();
}
/// Spawn channel receive task on the main event loop.
fn spawn_local_handler(label: gtk::Label, receiver: glib::Receiver<String>) {
receiver.attach(None, move |item| {
label.set_text(&item);
glib::Continue(true)
});
}
/// Spawn separate thread to handle communication.
fn start_communication_thread() -> (thread::JoinHandle<()>, Option<glib::Receiver<String>>) {
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let thr = thread::spawn(move || {
let mut counter = 0;
loop {
let data = format!("Counter = {}!", counter);
println!("Thread received data: {}", data);
if sender.send(data).is_err() {
break
}
counter += 1;
thread::sleep(std::time::Duration::from_millis(100));
}
});
(thr, Some(receiver))
}
As mentioned above, the only error remaining is that application.connect_activate() takes an Fn closure, the current implementation is FnMut.
The error message is:
error[E0596]: cannot borrow `receiver` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:17:31
|
17 | build_ui(application, receiver.take().unwrap())
| ^^^^^^^^ cannot borrow as mutable
So you cannot use "receiver" mutably, which is necessary for you to take() its contents.
But if you wrap the receiver inside a Cell, then you can access the immutable Cell's contents mutably. So add this line directly after the line with start_communication_thread():
let receiver = Cell::new(receiver);
There might be some more correct answer as I am only a beginner at Rust, but at least it seems to work.
Please note that this changes the take() call to be called against the Cell instead of Option, whose implementation has the same effect, replacing the Cell's contents with None.

Multithreaded Client that sends data in a queue and stores data in another, while not blocking in Rust Tokio

I'm having difficulties in making a Tokio client that receives packets from a server and stores them in a queue for the main thread to process, while being able to send packets to the server from another queue at the same time.
I'm trying to make a very simple online game demonstration, having a game client that Sends data (it's own modified states, like player movement) and receives data (Game states modified by other players & server, like an NPC/other players that also moved).
The idea is to have a network thread that accesses two Arcs holding Mutexes to Vec<bytes::Bytes> that store serialized data. One Arc is for IncomingPackets, and the other for OutgoingPackets. IncomingPackets would be filled by packets sent from the server to the client that would be later read by the main thread, and OutgoingPackets would be filled by the main thread with packets that should be sent to the server.
I can't seem to receive or send packets in another thread.
The client would only connect to the server, and the server would allow many clients (which would be served individually).
The explanations around stream's usage and implementation are not newbie-friendly, but I think I should be using them somehow.
I wrote some code, but it does not work and is probably wrong.
(My original code does not compile, so treat this as pseudocode, sorry)
Playground
extern crate byteorder; // 1.3.4
extern crate futures; // 0.3.5
extern crate tokio; // 0.2.21
use bytes::Bytes;
use futures::future;
use std::error::Error;
use std::sync::{Arc, Mutex};
use tokio::net::TcpStream;
use byteorder::{BigEndian, WriteBytesExt};
use std::io;
use std::time::Duration;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
use tokio::net::tcp::{ReadHalf, WriteHalf};
//This is the SharedPackets struct that is located in the crate structures
struct SharedPackets {
data: Mutex<Vec<bytes::Bytes>>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
let (mut r, mut w) = stream.split();
let mut inc: Vec<bytes::Bytes> = Vec::new();
inc.push(Bytes::from("Wow"));
let mut incoming_packets = Arc::new(SharedPackets {
data: Mutex::new(inc),
});
let mut outg: Vec<bytes::Bytes> = Vec::new();
outg.push(Bytes::from("Wow"));
let mut outgoint_packets = Arc::new(SharedPackets {
data: Mutex::new(outg),
});
let mut local_incoming_packets = Arc::clone(&incoming_packets);
let mut local_outgoint_packets = Arc::clone(&outgoint_packets);
let mut rarc = Arc::new(Mutex::new(r));
let mut warc = Arc::new(Mutex::new(w));
tokio::spawn(async move {
//send and receive are both async functions that contain an infinite loop
//they basically use AsyncWriteExt and AsyncReadExt to manipulate both halves of the stream
//send reads the queue and write this data on the socket
//recv reads the socket and write this data on the queue
//both "queues" are manipulated by the main thread
let mut read = &*rarc.lock().unwrap();
let mut write = &*warc.lock().unwrap();
future::try_join(
send(&mut write, &mut local_outgoint_packets),
recv(&mut read, &mut local_incoming_packets),
)
.await;
});
loop {
//read & write other stuff on both incoming_packets & outgoint_packets
//until the end of the program
}
}
async fn recv(reader: &mut ReadHalf<'_>, queue: &mut Arc<SharedPackets>) -> Result<(), io::Error> {
loop {
let mut buf: Vec<u8> = vec![0; 4096];
let n = match reader.read(&mut buf).await {
Ok(n) if n == 0 => return Ok(()),
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
return Err(e);
}
};
}
}
async fn send(writer: &mut WriteHalf<'_>, queue: &mut Arc<SharedPackets>) -> Result<(), io::Error> {
loop {
//task::sleep(Duration::from_millis(300)).await;
{
let a = vec!["AAAA"];
for i in a.iter() {
let mut byte_array = vec![];
let str_bytes = i.as_bytes();
WriteBytesExt::write_u32::<BigEndian>(&mut byte_array, str_bytes.len() as u32)
.unwrap();
byte_array.extend(str_bytes);
writer.write(&byte_array).await?;
}
}
}
}
This does not compile:
error: future cannot be sent between threads safely
--> src/main.rs:46:5
|
46 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::spawn`
|
= help: within `impl futures::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, tokio::net::tcp::ReadHalf<'_>>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:55:9
|
52 | let mut read = &*rarc.lock().unwrap();
| -------------------- has type `std::sync::MutexGuard<'_, tokio::net::tcp::ReadHalf<'_>>` which is not `Send`
...
55 | / future::try_join(
56 | | send(&mut write, &mut local_outgoint_packets),
57 | | recv(&mut read, &mut local_incoming_packets),
58 | | )
59 | | .await;
| |______________^ await occurs here, with `rarc.lock().unwrap()` maybe used later
60 | });
| - `rarc.lock().unwrap()` is later dropped here
help: consider moving this into a `let` binding to create a shorter lived borrow
--> src/main.rs:52:25
|
52 | let mut read = &*rarc.lock().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^
error: future cannot be sent between threads safely
--> src/main.rs:46:5
|
46 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.21/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ---- required by this bound in `tokio::spawn`
|
= help: within `impl futures::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, tokio::net::tcp::WriteHalf<'_>>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:55:9
|
53 | let mut write = &*warc.lock().unwrap();
| -------------------- has type `std::sync::MutexGuard<'_, tokio::net::tcp::WriteHalf<'_>>` which is not `Send`
54 |
55 | / future::try_join(
56 | | send(&mut write, &mut local_outgoint_packets),
57 | | recv(&mut read, &mut local_incoming_packets),
58 | | )
59 | | .await;
| |______________^ await occurs here, with `warc.lock().unwrap()` maybe used later
60 | });
| - `warc.lock().unwrap()` is later dropped here
help: consider moving this into a `let` binding to create a shorter lived borrow
--> src/main.rs:53:26
|
53 | let mut write = &*warc.lock().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^
I think this is the least of the problems, because I'm really new with tokio.
I could not find an example of this, do you know any performant approach to this problem?
Why don't you use channels for sending/receiveing data from/to other tasks?
There's a plenty of helpful examples here how to share data between tasks
EDIT: I looked at your code, noticed you're using wrong mutex. You should use tokio::sync::Mutex when dealing with async code. Secondly, there were issues with references in arc. I've moved creating arcs to spawned task and add cloning to send/reacv functions.
extern crate futures; // 0.3.5; // 0.1.36std;
extern crate tokio; // 0.2.21;
extern crate byteorder; // 1.3.4;
use std::{error::Error};
use std::sync::{Arc};
use tokio::sync::Mutex;
use tokio::net::TcpStream;
use futures::{future};
use bytes::Bytes;
use std::io;
use std::time::Duration;
use tokio::io::AsyncWriteExt;
use tokio::io::AsyncReadExt;
use tokio::net::tcp::{ReadHalf, WriteHalf};
use byteorder::{BigEndian, WriteBytesExt};
//This is the SharedPackets struct that is located in the crate structures
struct SharedPackets {
data: Mutex<Vec<bytes::Bytes>>
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let mut inc : Vec<bytes::Bytes> = Vec::new();
inc.push(Bytes::from("Wow"));
let mut incoming_packets = Arc::new(SharedPackets {
data: Mutex::new(inc)
});
let mut outg : Vec<bytes::Bytes> = Vec::new();
outg.push(Bytes::from("Wow"));
let mut outgoint_packets = Arc::new(SharedPackets {
data: Mutex::new(outg)
});
let mut local_incoming_packets = Arc::clone(&incoming_packets);
let mut local_outgoint_packets = Arc::clone(&outgoint_packets);
tokio::spawn(async move {
let mut stream = TcpStream::connect("127.0.0.1:8080").await.unwrap();
let (mut r, mut w) = stream.split();
let mut rarc = Arc::new(Mutex::new(& mut r));
let mut warc = Arc::new(Mutex::new(& mut w));
//send and receive are both async functions that contain an infinite loop
//they basically use AsyncWriteExt and AsyncReadExt to manipulate both halves of the stream
//send reads the queue and write this data on the socket
//recv reads the socket and write this data on the queue
//both "queues" are manipulated by the main thread
//let mut read = &*rarc.lock().await;
//let mut write = &*warc.lock().await;
future::try_join(send(warc.clone(), &mut local_outgoint_packets), recv(rarc.clone(), &mut local_incoming_packets)).await;
});
loop {
//read & write other stuff on both incoming_packets & outgoint_packets
//until the end of the program
}
}
async fn recv(readerw: Arc<Mutex<&mut ReadHalf<'_>>>, queue: &mut Arc<SharedPackets>) -> Result<(), io::Error> {
let mut reader = readerw.lock().await;
loop {
let mut buf : Vec<u8> = vec![0; 4096];
let n = match reader.read(&mut buf).await {
Ok(n) if n == 0 => return Ok(()),
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
return Err(e);
}
};
}
}
async fn send(writerw: Arc<Mutex<&mut WriteHalf<'_>>>, queue: &mut Arc<SharedPackets>) -> Result<(), io::Error> {
let mut writer = writerw.lock().await;
loop{
//task::sleep(Duration::from_millis(300)).await;
{
let a = vec!["AAAA"];
for i in a.iter() {
let mut byte_array = vec![];
let str_bytes = i.as_bytes();
WriteBytesExt::write_u32::<BigEndian>(&mut byte_array, str_bytes.len() as u32).unwrap();
byte_array.extend(str_bytes);
writer.write(&byte_array).await?;
}
}
}
}
Here is full code without errors, didn't test it though: Playground link
Here's an example that's a bit contrived, but it should help:
Playground link
use std::{sync::Arc, time::Duration};
use tokio::{self, net::TcpStream, sync::Mutex};
#[tokio::main]
async fn main() {
let mut incoming_packets = Arc::new(Mutex::new(vec![b"Wow".to_vec()]));
let mut local_incoming_packets = incoming_packets.clone();
tokio::spawn(async move {
for i in 0usize..10 {
tokio::time::delay_for(Duration::from_millis(200)).await;
let mut packets = local_incoming_packets.lock().await;
packets.push(i.to_ne_bytes().to_vec());
}
});
loop {
tokio::time::delay_for(Duration::from_millis(200)).await;
let packets = incoming_packets.lock().await;
dbg!(packets);
}
}
You can see that I have to clone outside of the async move block since that block takes ownership of everything inside it. I'm not sure about r and w but you might need to move those inside the block as well before you can pass mutable references to them. I can update my answer if you provide code that includes all of the proper use statements.
One thing that you need to remember is that main() can technically exit before the code that has been spawned.
Also, note that I used tokio::sync::Mutex so that you can yield while waiting to acquire the lock.

Split a futures connection into a sink and a stream and use them in two different tasks

I'm experimenting with the futures API using the websocket library. I have this code:
use futures::future::Future;
use futures::future;
use futures::sink::Sink;
use futures::stream::Stream;
use futures::sync::mpsc::channel;
use futures::sync::mpsc::{Sender, Receiver};
use tokio_core::reactor::Core;
use websocket::{ClientBuilder, OwnedMessage};
pub fn main() {
let mut core = Core::new().unwrap();
let handle = core.handle();
let handle_clone = handle.clone();
let (send, recv): (Sender<String>, Receiver<String>) = channel(100);
let f = ClientBuilder::new("wss://...")
.unwrap()
.async_connect(None, &handle_clone)
.map_err(|e| println!("error: {:?}", e))
.map(|(duplex, _)| duplex.split())
.and_then(move |(sink, stream)| {
// this task consumes the channel, writes messages to the websocket
handle_clone.spawn(future::loop_fn(recv, |recv: Receiver<String>| {
sink.send(OwnedMessage::Close(None))
.and_then(|_| future::ok(future::Loop::Break(())))
.map_err(|_| ())
}));
// the main tasks listens the socket
future::loop_fn(stream, |stream| {
stream
.into_future()
.and_then(|_| future::ok(future::Loop::Break(())))
.map_err(|_| ())
})
});
loop {
core.turn(None)
}
}
After connecting to the server, I want to run "listener" and "sender" tasks without one blocking the other one. The problem is I can't use sink in the new task, it fails with:
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> src/slack_conn.rs:29:17
|
25 | .and_then(move |(sink, stream)| {
| ---- captured outer variable
...
29 | sink.send(OwnedMessage::Close(None))
| ^^^^ cannot move out of captured outer variable in an `FnMut` closure
I could directly use duplex to send and receive, but that leads to worse errors.
Any ideas on how to make this work? Indeed, I'd be happy with any futures code that allows me to non-blockingly connect to a server and spawn two async tasks:
one that reads from the connection and takes some action (prints to screen etc.)
one that reads from a mpsc channel and writes to the connection
It's fine if I have to write it in a different style.
SplitSink implements Sink which defines send to take ownership:
fn send(self, item: Self::SinkItem) -> Send<Self>
where
Self: Sized,
On the other hand, loop_fn requires that the closure be able to be called multiple times. These two things are fundamentally incompatible — how can you call something multiple times which requires consuming a value?
Here's a completely untested piece of code that compiles — I don't have rogue WebSocket servers lying about.
#[macro_use]
extern crate quick_error;
extern crate futures;
extern crate tokio_core;
extern crate websocket;
use futures::{Future, Stream, Sink};
use futures::sync::mpsc::channel;
use tokio_core::reactor::Core;
use websocket::ClientBuilder;
pub fn main() {
let mut core = Core::new().unwrap();
let handle = core.handle();
let (send, recv) = channel(100);
let f = ClientBuilder::new("wss://...")
.unwrap()
.async_connect(None, &handle)
.from_err::<Error>()
.map(|(duplex, _)| duplex.split())
.and_then(|(sink, stream)| {
let reader = stream
.for_each(|i| {
println!("Read a {:?}", i);
Ok(())
})
.from_err();
let writer = sink
.sink_from_err()
.send_all(recv.map_err(Error::Receiver))
.map(|_| ());
reader.join(writer)
});
drop(send); // Close the sending channel manually
core.run(f).expect("Unable to run");
}
quick_error! {
#[derive(Debug)]
pub enum Error {
WebSocket(err: websocket::WebSocketError) {
from()
description("websocket error")
display("WebSocket error: {}", err)
cause(err)
}
Receiver(err: ()) {
description("receiver error")
display("Receiver error")
}
}
}
The points that stuck out during implementation were:
everything has to become a Future eventually
it's way easier to define an error type and convert to it
Knowing if the Item and Error associated types were "right" was tricky. I ended up doing a lot of "type assertions" ({ let x: &Future<Item = (), Error = ()> = &reader; }).

Concurrent access to vector from multiple threads using a mutex lock

I'm using an example provided by the Tokio library and attempting to have a vector of all the currently active TCP connections. Ultimately, I would like to be able to broadcast a message to each of the active connections, by looping through them and writing a message to the socket.
To start with, I am trying to print out the current number of connections in one thread whilst accepting connections in another.
To do this, I'm trying to use a shared vector. I've not yet implemented the removal of connections from the vector as and when they disconnect.
// A tiny async echo server with tokio-core
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
use futures::{Future, Stream};
use tokio_io::{io, AsyncRead};
use tokio_core::net::TcpListener;
use tokio_core::reactor::Core;
use std::thread;
use std::sync::{Arc, Mutex};
use std::io::stdout;
use std::io::Write;
fn main() {
// Create the event loop that will drive this server
let mut core = Core::new().unwrap();
let handle = core.handle();
// Bind the server's socket
let addr = "127.0.0.1:12345".parse().unwrap();
let tcp = TcpListener::bind(&addr, &handle).unwrap();
let mut connections = Arc::new((Mutex::new(Vec::new())));
thread::spawn(move || {
//Every 10 seconds print out the current number of connections
let mut i;
loop {
i = connections.lock().unwrap().len();
println!("There are {} connections", i);
stdout().flush();
thread::sleep_ms(10000);
}
});
// Iterate incoming connections
let server = tcp.incoming().for_each(|(tcp, _)| {
connections.lock().unwrap().push(tcp);
// Split up the read and write halves
let (reader, writer) = tcp.split();
// Future of the copy
let bytes_copied = io::copy(reader, writer);
// ... after which we'll print what happened
let handle_conn = bytes_copied.map(|(n, _, _)| {
println!("wrote {} bytes", n)
}).map_err(|err| {
println!("IO error {:?}", err)
});
// Spawn the future as a concurrent task
handle.spawn(handle_conn);
Ok(())
});
// Spin up the server on the event loop
core.run(server).unwrap();
}
At the moment this is failing to build with the following errors:
error[E0382]: capture of moved value: `connections`
--> src/main.rs:36:42
|
26 | thread::spawn(move || {
| ------- value moved (into closure) here
...
36 | let server = tcp.incoming().for_each(|(tcp, _)| {
| ^^^^^^^^^^ value captured here after move
|
= note: move occurs because `connections` has type `std::sync::Arc<std::sync::Mutex<std::vec::Vec<tokio_core::net::TcpStream>>>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `tcp`
--> src/main.rs:40:32
|
38 | connections.lock().unwrap().push(tcp);
| --- value moved here
39 | // Split up the read and write halves
40 | let (reader, writer) = tcp.split();
| ^^^ value used here after move
|
= note: move occurs because `tcp` has type `tokio_core::net::TcpStream`, which does not implement the `Copy` trait
Is it possible to achieve this without writing any unsafe code?
You get the first error because of the move closure:
let mut connections = Arc::new((Mutex::new(Vec::new())));
thread::spawn(move || {
let mut i = connections.lock().unwrap().len();
....
}
This actually moves the whole Arc, while you only want to move "a part" of it (that is, move it in such a way that the reference count is incremented, and that both threads can use it).
To do this, we can use Arc::clone:
let mut connections = Arc::new((Mutex::new(Vec::new())));
let conn = connections.clone();
thread::spawn(move || {
let mut i = conn.lock().unwrap().len();
....
}
This way, the cloned Arc, conn, is moved into the closure, and the original Arc, connections, is not, and hence still usable.
I'm not sure exactly what you are doing with your second error, but for the sake of simply counting the connections you do not need to push the entire thing.

Resources