I have construction like Arc<RwLock<Option<Channel<Msg>>>> and I can't understand why it isn't Send + Sync. RwLock must make it Sync and Arc must make it Send?
Whole example:
use std::sync::{
mpsc::{Receiver, Sender},
Arc,
};
use tokio::sync::RwLock;
struct Channel<Msg: Send + Sync + 'static> {
tx: Sender<Msg>,
rx: Receiver<Msg>,
}
struct Data<Msg: Send + Sync + 'static> {
channel: Arc<RwLock<Option<Channel<Msg>>>>,
}
fn spawn<Msg: Send + Sync>(data: Data<Msg>) {
tokio::task::spawn(async move {
let data = data.channel.write().await.take().unwrap();
while let Ok(msg) = data.rx.recv() {
drop(msg);
}
println!("recv() not ok.")
});
}
#[tokio::main]
async fn main() {}
Before I address your question, it is very important that you do not use the std channels in async code. Use the tokio::sync::mpsc channel instead. Read this article for more info on why.
Now, to answer your question, the Channel type is Send + !Sync because that's what std::sync::mpsc::Sender is. Now, the RwLock has the following impls:
impl<T: Send> Send for RwLock<T> {}
impl<T: Send + Sync> Sync for RwLock<T> {}
So since T is not Sync, neither is the RwLock. Then, the Arc has the following impl:
impl<T: Send + Sync> Send for Arc<T> {}
impl<T: Send + Sync> Sync for Arc<T> {}
But the RwLock<T> is not Sync, so the Arc becomes neither Send nor Sync.
Unrelated, but as a matter of code design, putting a channel sender or receiver in a mutex or rwlock is almost always a mistake.
Using the std channel in async code is simply not possible. If the channels come from a library, then you're going to have to spawn a dedicated thread for managing the channels.