Avoid double locking when sharing `Stdout` across threads

I have a program where I have multiple threads writing to the same io. The multithreaded writing function is generic over the writer type W: Write + Send, but the type defaults to stdout.

Currently, I handle this by sending an Arc<Mutex<W>> to each thread. That works fine, and I should probably just leave it at that.

However, I noticed that the Stdout type itself contains a Mutex. So, my current solution locks twice on each write: First it locks the mutex I created to access the Stdout, and then it locks the Stdout. I wonder if there is a way to only make it lock once for Stdout, while still having the function be generic over writer types.

I've tried the following things:

  • Share an Arc<W> where for<'a> &'a T: Write. This doesn't work, because even though &W: Write, I still need a mutable reference to actually call .write.
  • Require W: Write + Send + Clone, then clone the W and send a copy to each thread. However, Stdout does not implement Clone.

Is there a way to handle this?

In case &T: Write, you can use &*w to turn Arc<W> into &W which implements Write. So for example:

use std::io::Write;
use std::sync::Arc;

fn foo<W>(mut w: Arc<W>) where for<'a> &'a W: Write {
    (&*w).write(b"foo").unwrap();
}

fn main () {
    foo(Arc::new(std::io::stdout()));
}
1 Like

Thank you, this works perfectly. Actually, I figured I can completely dispense with Arc in the signature, and require W: Send + Sync, for<'a> &'a W: Write. Then I can send this shared reference to all threads. This applies to Stdout, and I can make a wrapper struct that uses Arc and Mutex internally.
Thank you again.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.