0

I am trying to store the state of my app which includes a list of traits that are initialized in the beginning and pass the state between multiple threads but I am getting an error.

use std::sync::{Arc, RwLock};
use std::thread;
use std::time::Duration;

trait TestTrait {
    fn test(&self);
}

struct MyTestStruct {}

impl TestTrait for MyTestStruct {
    fn test(&self) {
        println!("Test trait called");
    }
}

struct DataStore {
    t: Box<dyn TestTrait>,
}

fn main() {
    let s = Arc::new(RwLock::new(DataStore {
        t: Box::new(MyTestStruct {}),
    }));
    let s_clone = s.clone();
    thread::spawn(move || {
        for i in 1..10 {
            s_clone.read().unwrap().t.test();
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

When I run this, I get the following error:

error[E0277]: `(dyn TestTrait + 'static)` cannot be sent between threads safely
   --> src/main.rs:26:5
    |
26  |     thread::spawn(move || {
    |     ^^^^^^^^^^^^^ `(dyn TestTrait + 'static)` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `(dyn TestTrait + 'static)`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn TestTrait + 'static)>`
    = note: required because it appears within the type `std::boxed::Box<(dyn TestTrait + 'static)>`
    = note: required because it appears within the type `DataStore`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::RwLock<DataStore>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::RwLock<DataStore>>`
    = note: required because it appears within the type `[closure@src/main.rs:26:19: 32:6 s_clone:std::sync::Arc<std::sync::RwLock<DataStore>>]`

error[E0277]: `(dyn TestTrait + 'static)` cannot be shared between threads safely
   --> src/main.rs:26:5
    |
26  |     thread::spawn(move || {
    |     ^^^^^^^^^^^^^ `(dyn TestTrait + 'static)` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `(dyn TestTrait + 'static)`
    = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn TestTrait + 'static)>`
    = note: required because it appears within the type `std::boxed::Box<(dyn TestTrait + 'static)>`
    = note: required because it appears within the type `DataStore`
    = note: required because of the requirements on the impl of `std::marker::Sync` for `std::sync::RwLock<DataStore>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::RwLock<DataStore>>`
    = note: required because it appears within the type `[closure@src/main.rs:26:19: 32:6 s_clone:std::sync::Arc<std::sync::RwLock<DataStore>>]`

How do I fix this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
S Poudel
  • 3
  • 1

1 Answers1

8

thread::spawn requires a closure that implements Send. Arc<T> only implements Send if T implements both Send and Sync.

Send and Sync are auto traits. You can add auto traits to a dyn Trait type to provide more information about the erased type:

struct DataStore {
    t: Box<dyn TestTrait + Send + Sync>,
}

If you are going to write dyn TestTrait + Send + Sync everywhere, then another option is to declare Send and Sync as supertraits of TestTrait:

trait TestTrait: Send + Sync {
    fn test(&self);
}
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155