在Rust中,在线程内访问自身的方法

6
我希望您能将self结构体对象传递到线程中,然后调用它的time_tick()方法以增加HMS时间。
pub fn start(&mut self) {
    self.acti = true;   // the time tick is activated now...
    thread::spawn(move || {
        let local_self: *mut Self = self;   // this self live in the thread
        loop {
            thread::sleep(Duration::from_secs(1));  // wait for 1 sec
            if (*local_self).acti == true { (*local_self).time_tick(); }    
            (*local_self).print_time();  // for debug
        }
    });
}

我收到了这个错误信息:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/hmstimer/mod.rs:42:17
   |
42 |           thread::spawn(move || {
   |  _______________________^
43 | |             let local_self: *mut Self = self;   // this self live in the thread
44 | |             loop {
45 | |                 thread::sleep(Duration::from_secs(1));    // wait for 1 sec
...  |
48 | |             }
49 | |         });
   | |_________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 40:2...
  --> src/hmstimer/mod.rs:40:2
   |
40 |       pub fn start(&mut self) {
   |  _____^
41 | |         self.acti = true;    // the time tick is activated now...
42 | |         thread::spawn(move || {
43 | |             let local_self: *mut Self = self;   // this self live in the thread
...  |
49 | |         });
50 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &mut hmstimer::HMSTimer
              found &mut hmstimer::HMSTimer
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/hmstimer/mod.rs:42:17: 49:7 self:&mut hmstimer::HMSTimer]` will meet its required lifetime bounds

但是看起来关于方法似乎不合适。有什么最佳实践来完成这个任务吗?


1
你正在尝试启动一个每秒钟使用self的无限线程。当self被销毁时,你期望它会做什么?这就是为什么Rust禁止这样做的完美理由。 - mcarton
在线程内部使用local_self怎么样?但是我的定义似乎不正确... - Casper
1
self的类型是&mut Self,所以&mut self的类型是&mut &mut Self。错误信息应该很明显,所以请在问题中始终包含它。然而,修复类型问题并不能解决@mcarton提到的生命周期问题。 - Sven Marnach
if (*local_self).acti == true — 这是多余的。只需使用 if local_self.acti。同样适用于 local_self.time_tick()local_self.print_time() - Shepmaster
1个回答

6
您不能将捕获可变引用的闭包传递给thread::spawnthread::spawn需要函数是'static,这意味着它要么不捕获任何借用,要么所有的借用都是'static。这是因为线程在引用已被丢弃后仍可以继续运行。
如果您在调用start后原始线程中不需要使用self,那么只需按值传递self即可。
pub fn start(self) {
    self.acti = true;
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(1));
            if self.acti == true { self.time_tick(); }    
            self.print_time();
        }
    });
}

否则,你需要使用 Arc 来让两个线程共享对 Self 的所有权,同时使用 Mutex 或者 RwLock 以在线程间同步读写操作。
// note: this is not a method anymore;
// invoke as `HMSTimer::start(arc.clone());`
pub fn start(this: Arc<Mutex<Self>>) {
    this.lock().expect("mutex is poisoned").acti = true;
    thread::spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(1));
            let lock = this.lock().expect("mutex is poisoned");
            if lock.acti == true { lock.time_tick(); }    
            lock.print_time();
            // `lock` is dropped here, unlocking the mutex
        }
    });
}

当我试图在线程闭包中锁定this时,出现了以下错误:\(dyn for<'r> std::ops::Fn(&'r str) + 'static)`不能在线程之间安全地发送。 - Beat Scherrer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接