Rust调用Mutex包裹的Worker的join方法报移出解引用值错误如何解决
你的Worker::join方法签名是fn join(self),要求获取Worker实例的完整所有权才能调用,但self.internal.lock().unwrap()拿到的是MutexGuard智能指针,解引用后只能得到Worker的可变借用,无法直接转移所有权,因此触发编译错误。
本质上Arc<Mutex<Worker>>的设计是多所有者共享内部的Worker实例,Rust所有权规则禁止你从共享容器中直接移走内部值,否则其他持有Arc的所有者会访问到已失效的内存。
推荐方案:修改Worker::join签名,仅转移JoinHandle所有权
你不需要消费整个Worker实例,只需要拿到thread_join_handle的所有权就可以调用join方法,使用Option::take即可从可变借用中取出JoinHandle,同时将原字段置为None,完全符合安全规则。
修改后的代码如下:
impl Worker { // 签名改为接收&mut self,不需要所有权 fn join(&mut self) { // 用take取出Option里的JoinHandle,原字段变为None if let Some(thread_join_handle) = self.thread_join_handle.take() { thread_join_handle.join().expect("Couldn't join the associated threads.") } } fn perform_random_transactions(&self) { } }
ArcWorker的join方法不需要做任何修改,MutexGuard提供的可变借用刚好可以调用修改后的join方法。
该方案不会破坏Worker的共享属性,调用join后Worker的其他字段依然可以正常访问。
备选方案:消费ArcWorker获取Worker所有权
如果你确定调用join后不需要再使用ArcWorker实例,且此时没有其他Arc持有者共享该Worker,可以直接拆包Arc拿到Worker的完整所有权:
impl ArcWorker { // 签名改为接收self所有权,调用后ArcWorker被消费 pub fn join(self) { // 拆包Arc,要求当前只有一个强引用 let mutex = Arc::try_unwrap(self.internal).unwrap(); // 拆包Mutex拿到内部Worker的所有权 let worker = mutex.into_inner().unwrap(); worker.join(); } }
该方案的局限性较大,仅适合ArcWorker是唯一持有者、且join是最后一次调用的场景。
为了避免持有Mutex锁期间等待线程退出带来的潜在死锁风险,你可以把JoinHandle取出后先释放锁再执行join,修改后的Worker::join逻辑如下:
fn join(&mut self) { let handle = self.thread_join_handle.take(); // 此处Mutex锁会被提前释放,不需要持有锁等待线程结束 if let Some(h) = handle { h.join().expect("Couldn't join the associated threads."); } }
内容的提问来源于stack exchange,提问作者Alexandru Robert

