Как определить тип замыкания для безопасной отправки в поток - PullRequest
2 голосов
/ 12 апреля 2020

Я пытаюсь отправить замыкание в поток для обработки следующим образом:

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();
}

Но я получаю сообщение об ошибке: F невозможно безопасно переслать между потоками

В широком обзоре мне нужно сделать это (код компилируется):

let closure = || env_variable.to_string();

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

Как я могу определить F, чтобы я мог отправить его в поток, учитывая, что мне нужно захватить среду .

1 Ответ

4 голосов
/ 13 апреля 2020

Если вы посмотрите на thread::spawn или thread::Builder::spawn, вы увидите, что у него есть подпись

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

Это означает, что оба закрытие потока f и его возвращаемое значение должны реализовывать черту Send (т. е. быть отправляемой по потокам) и иметь время жизни 'static (т. е. не иметь заимствований с незавершенным c время жизни.

Закрытие будет Send, если все его захваченные переменные равны. Также будет 'static, если все его захваченные переменные и все захваченные переменные перемещены в замыкание (что и делает ключевое слово move).

Поскольку единственная захваченная переменная в твоем замыкании work_load, вам нужно убедиться, что work_load равно Send и 'static:

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