【问题标题】:How to define closure type to send into thread safetly如何定义闭包类型以发送到线程安全
【发布时间】:2020-04-12 20:42:41
【问题描述】:

我正在尝试将闭包发送到线程中以进行如下处理:

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 以便将其发送到线程中。

【问题讨论】:

    标签: rust thread-safety closures


    【解决方案1】:

    如果您查看thread::spawnthread::Builder::spawn,您会看到它有签名

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

    这意味着线程闭包f 及其返回值都必须实现Send 特征(即可跨线程发送)并具有'static 生命周期(即没有任何非静态生命周期的借用) )。

    如果所有捕获的变量都是,则闭包将为Send。如果所有捕获的变量都在并且所有捕获的变量都被移动到闭包中(这就是 move 关键字的作用),它也将是 'static

    由于闭包中唯一捕获的变量是work_load,因此您需要确保work_load 既是Send 又是'static

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

    【讨论】:

    • 太好了,谢谢。我会看看那些+,因为我正在学习 Rust,但不知道那种类型的组合或交集。
    • 注意:闭包的参数也需要为Send + 'staticSend 是必要的,因为必须将内容发送到线程边界之外。例如,您可以将不是Send 的内容包装在Arc 中,以解决此限制(还有其他方法)。 'static 生命周期是必需的,因为线程可以分离并且比主线程存活的时间更长。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    • 2016-06-16
    • 1970-01-01
    相关资源
    最近更新 更多