Lifetime woes when using threads

一曲冷凌霜 提交于 2019-11-30 05:00:05

问题


I'm having a hard time getting this to compile:

use std::thread::{self, JoinHandle};

struct Foo<'c> {
    foo: &'c str,
}

impl<'c> Foo<'c> {
    fn use_in_another_thread<F>(self, mut cb: F) -> JoinHandle<Foo<'c>>
        where F: FnOnce(&mut Foo),
              F: Send
    {
        thread::spawn(move || {
            cb(&mut self);
            self
        })
    }
}

fn main() {}

As far as I can see the lifetimes are sound, but I'm getting errors...

error[E0477]: the type `[closure@src/main.rs:12:23: 15:10 cb:F, self:Foo<'c>]` does not fulfill the required lifetime
  --> src/main.rs:12:9
   |
12 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^
   |
   = note: type must outlive the static lifetime

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:14:13
   |
14 |             self
   |             ^^^^
   |
note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 11:4...
  --> src/main.rs:11:5
   |
11 |       {
   |  _____^ starting here...
12 | |         thread::spawn(move || {
13 | |             cb(&mut self);
14 | |             self
15 | |         })
16 | |     }
   | |_____^ ...ending here
note: ...so that expression is assignable (expected std::thread::JoinHandle<Foo<'c>>, found std::thread::JoinHandle<Foo<'_>>)
  --> src/main.rs:12:9
   |
12 |           thread::spawn(move || {
   |  _________^ starting here...
13 | |             cb(&mut self);
14 | |             self
15 | |         })
   | |__________^ ...ending here
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `Foo<'_>` will meet its required lifetime bounds
  --> src/main.rs:12:9
   |
12 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^

I don't understand what lifetimes the errors are referring to - the lifetime of the closure body? - or why they must outlive the static lifetime.


回答1:


The lifetime constraint that is causing this problem is the one in Thread::spawn, which requires the FnOnce closure to be Send. Send requires 'static, which means that the data contains no non-'static data. Your data, Foo, contains a borrowed str, which is not 'static, which makes Foo non-'static. As a result, you can't send Foo across threads.

Why is this? Since Foo contains a borrow, it is valid for only a small lifetime. If Rust allowed you to send an instance of Foo to another thread, then that thread could easily use Foo long after the data it borrows has become invalid.

You might think that this is actually overly restrictive, and you'd be right. There's no reason to not allow local parallelism as long as you can prove to the borrow checker that the thread terminates within some lifetime. There are currently no constructs in Rust to do this, but there are some future solutions for this problem, such as this RFC which extends the Send trait to allow local parallelism.



来源:https://stackoverflow.com/questions/27754877/lifetime-woes-when-using-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!