X cannot be sent between threads safely

Hi everyone !

I have an issue passing my Client instance into separate task:

let task1 = tokio::spawn(async move {
    Client::new().run(RunOptions {
        // ... params
    }).await.unwrap();
});

there two errors:

error[E0277]: `dyn Feature` cannot be sent between threads safely
   --> src/main.rs:16:17
    |
16  |     let task1 = tokio::spawn(async move {
    |                 ^^^^^^^^^^^^ `dyn Feature` cannot be sent between threads safely

and

error[E0277]: `std::sync::MutexGuard<'_, tentacli::primary::shared::session::Session>` cannot be sent between threads safely
   --> src/main.rs:16:17
    |
16  |       let task1 = tokio::spawn(async move {
    |  _________________^^^^^^^^^^^^_-
    | |                 |
    | |                 `std::sync::MutexGuard<'_, tentacli::primary::shared::session::Session>` cannot be sent between threads safely

first error I fixed by adding Send condition to my trait:

pub trait Feature: Send {
    fn new(
        sender: BroadcastSender<HandlerOutput>,
        receiver: BroadcastReceiver<HandlerOutput>,
    ) -> Self where Self: Sized;

    fn get_tasks(&mut self) -> Vec<JoinHandle<()>>;
}

but I am not sure how to fix mutex error. It is not clear why I do not receive this error when Client run without task (considering, Client itself use multiple task internally). I use this mutex inside Client's own tasks and app compiles successfully.

Could you please explain why this issue happen and how to fix it ? I believe I should not move all my mutex to tokio async mutex.

There isn't really much to explain here. The future you pass to tokio::spawn must be Send and yours captures a MutexGuard which is decidedly not Send, making the whole future !Send as well.

1 Like

So, to make it Send I should avoid std::sync::Mutex and replace it with tokio::sync::Mutex ?

That could solve your problem, yes. Tokio's MutexGuard implements Send if the inner type is Send, too.

1 Like

Thank you for the explanation !

This section of the Tokio tutorial discusses three possible approaches when a mutex is needed. Using a Tokio async mutex as already mentioned is one solution. The other two are:

Restructure your code to not hold the lock across an .await

Spawn a task to manage the state and use message passing to operate on it

5 Likes

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.