How to use TcpStream with Arc

Viewed 364

I have a TcpStream, and i'm trying to create a dedicated thread to read from TcpStream and the main thread should do the write only, so i wrapped the TcpStream inside an Arc to share ownership. Here is my code

fn main() {
    let mut tcp_stream = TcpStream::connect("127.0.0.1:8080").unwrap();
    let tcp_stream = Arc::new(&mut tcp_stream);
}
fn read_from_stream(tcp_stream: Arc<&mut TcpStream>) {
    let mut buffer = String::new();
    tcp_stream.read_to_string(&mut buffer);
}

I got the error Cannot borrow data in Arc as mutable. But the tcp_stream needs to be mutable in order to call read_to_string method. What should i do to make this work?

2 Answers

From the docs:

Shared references in Rust disallow mutation by default, and Arc is no exception: you cannot generally obtain a mutable reference to something inside an Arc. If you need to mutate through an Arc, use Mutex, RwLock, or one of the Atomic types.

In your case, I would go either with Mutex or RwLock.

Example using Mutex:

fn main()
{
    let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
    let stream = Arc::new(Mutex::new(stream));
    read_from_stream(stream);
}

fn read_from_stream(tcp_stream: Arc<Mutex<TcpStream>>)
{
    let mut buffer = String::new();

    let mut tcp_stream = tcp_stream.lock().unwrap();
    tcp_stream.read_to_string(&mut buffer).unwrap();
}

While Arc does inhibit mutability, in this case that's not an issue because &TcpStream implements Read.

Therefore you can wrap TcpStream (not &mut TcpStream) in Arc and call read_to_string() on the shared &TcpStream reference obtained with Arc::as_ref():

fn main() {
    let tcp_stream = TcpStream::connect("127.0.0.1:8080").unwrap();
    let tcp_stream = Arc::new(tcp_stream);
}

fn read_from_stream(tcp_stream: Arc<TcpStream>) {
    let mut buffer = String::new();
    tcp_stream.as_ref().read_to_string(&mut buffer);
}

Playground

Related