kumarmo2
kumarmo2

Reputation: 1393

Cannot Send A Struct Across Threads which has mpsc::Sender as field

I have a struct which has Sender type as its field.

pub struct GenericConnectionPool<E>
where
    E: ConnectionConnector,
{
    _sender: Sender<()>,
    _reciever: Arc<Mutex<Receiver<()>>>,
    _num_of_live_connections: AtomicU8,
    _max_connections: u8,
    _min_connections: u8,
    _connections: Arc<Mutex<Vec<<E as ConnectionConnector>::Conn>>>,
    _connector: E,
}

I am using the struct across multiple threads, that is why, while using it inside Arc and clone it.

let pool = Arc::new(GenericConnectionPool::new(2, 1, cc));
println!("here");
{
    for _ in 0..3 {
        let pool = Arc::clone(&pool);
        std::thread::spawn(move || {
            pool.get_connection();
            thread::sleep(Duration::from_secs(1));
        });
    }
}

But I am getting the error that my struct cannot be sent across threads.

`std::sync::mpsc::Sender<()>` cannot be shared between threads safely
within `GenericConnectionPool<tests::connector_works::DummyConnectionConnector>`, the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>`
required because it appears within the type `GenericConnectionPool<tests::connector_works::DummyConnectionConnector>`
required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<GenericConnectionPool<tests::connector_works::DummyConnectionConnector>>`
required because it appears within the type `[closure@src/lib.rs:169:36: 172:18 pool:std::sync::Arc<GenericConnectionPool<tests::connector_works::DummyConnectionConnector>>]`

What I understood is that the Sender type cannot be sent safely across threads, but since its cloneable, you can clone it and then send it across the thread. But in my situation, sender is inside my Struct. I can't figure out a way to fix this.

I am thinking I might have to change my design.

Upvotes: 0

Views: 379

Answers (1)

Michael Anderson
Michael Anderson

Reputation: 73480

You could use Crossbeam. Its crossbeam::Sender seems to be transferable between threads. Presumably, you'd need to use its crossbeam::Receiver too.

Alternatively, you could refactor your GenericConnectionPool to be like this:

pub struct ExtraData {}

#[derive(Clone)]
pub struct GenericConnectionPool {
    _sender: Sender<()>,
    _extra_data: Arc<ExtraData>,
}

then you can clone the GenericConnectionPool directly rather than an Arc containing it and get the correct behaviour:

let pool = GenericConnectionPool{_sender:s, _extra_data:Arc::new(ExtraData{}) };

for _ in 0..3 {
   let pool = pool.clone();
   std::thread::spawn(move || {
       pool.get_connection();
       thread::sleep(Duration::from_secs(1));
    });
}

You can see a compiling version here:

Upvotes: 2

Related Questions