Miguel Lattuada
Miguel Lattuada

Reputation: 5407

How to define closure type to send into thread safetly

I'm trying to send a closure into a thread to process like:

fn spawn<F>(work_load: F) where F: FnMut() {
    let builder = Builder::new();
    let handler = builder.spawn(move || {
        // Before process
        work_load();
        // After process
    }).unwrap();
}

But I'm getting an error: F cannot be sent between threads safely

In a high overview I need to do this (code compiles):

let closure = || env_variable.to_string();

thread::spawn(move || {
    // before closure
    closure();
    // after closure
});

How I can define F so I can send it into thread, considering I need to capture environment.

Upvotes: 2

Views: 1458

Answers (1)

Freyja
Freyja

Reputation: 40814

If you have a look at thread::spawn or thread::Builder::spawn, you will see that it has the signature

pub fn spawn<F, T>(f: F) -> JoinHandle<T> 
where
    F: FnOnce() -> T,
    F: Send + 'static,
    T: Send + 'static, 

This means that both the thread closure f and its return value must implement the Send trait (i.e. be sendable across threads) and have a 'static lifetime (i.e. not have any borrows with a non-static lifetime).

A closure will be Send if all of its captured variables are. It will also be 'static if all of its captured variables are and all captured variables are moved into the closure (which is what the move keyword does).

Since the only captured variable in your closure is work_load, you need to ensure that work_load is both Send and 'static:

fn spawn<F>(work_load: F)
where
    F: FnMut() + Send + 'static
//               ^---.---^
//                   \_ add these constraints to F

Upvotes: 5

Related Questions