Rust中如何传递非静态可变数据给线程并确保其在join前不销毁?
多线程处理Vec的生命周期问题及解决方案
问题背景
我需要将一个Vec拆分为多个块分配给不同线程处理,在所有线程调用join()确认不再访问该Vec后返回它。但线程要求数据必须具有'static生命周期以防止访问时被销毁,请问有什么解决办法?
我尝试过以下两种方式,但都存在弊端:
- 使用
Arc和Mutex:会限制原数据的可变性 - 让每个线程返回Vec再合并:对于3840*2160尺寸的Vec来说,效率极低
报错代码
{ let mut data: Vec<u8> = vec![0; (render_config.resolution.0 * render_config.resolution.1 * 3) as usize]; let chunks = data.chunks_mut(((render_config.resolution.0 * render_config.resolution.1 * 3) / 12) as usize); let mut ts = Vec::with_capacity(chunks.len()); let mut offset = 0; for chunk in chunks { ts.push(thread::spawn(|| { Self::get_image_sub_threaded(self.clone(), render_config.clone(), is_screenshot, chunk, offset); })); offset += chunk.len(); } for t in ts { t.join(); } data }
错误信息
error[E0597]: `data` does not live long enough --> src\rendering\camera.rs:26:22 | 26 | let chunks = data.chunks_mut(((render_config.resolution.0 * render_config.resolution.1 * 3) / 12) as usize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... 32 | ts.push(thread::spawn(|| { Self::get_image_sub_threaded(self.clone(), render_config.clone(), is_screenshot, chunk, offset); })); | ---------------------------------------------------------------------------------------------------------------------- argument requires that `data` is borrowed for `'static` ... 41 | } | - `data` dropped here while still borrowed
解决方案:使用thread::scope
thread::scope可以创建一个线程作用域,作用域内的线程可以安全引用作用域内的变量,无需满足'static生命周期约束,同时保证所有线程在作用域结束前完成执行,不会出现悬垂引用。以下是实现代码:
pub fn get_image_threaded(&self, render_config: &RenderConfig) -> Vec<u8> { let mut data: Vec<u8> = vec![0; (render_config.screenshot_resolution.0 * render_config.screenshot_resolution.1 * 3) as usize]; let chunks = data.chunks_mut(((render_config.screenshot_resolution.0 * render_config.screenshot_resolution.1 * 3) as usize) / num_cpus::get()); println!("CPUs available: {}", num_cpus::get()); thread::scope(|scope| { let mut ts = Vec::with_capacity(chunks.len()); let mut offset = 0; let mut i: u32 = 0; for chunk in chunks { let o = offset; let len = chunk.len() / 3; ts.push(scope.spawn(move || { Self::get_image_sub_threaded(self.clone(), render_config.clone(), true, chunk, o, i); })); offset += len; i += 1; } for t in ts { t.join().unwrap(); } }); data }
内容的提问来源于stack exchange,提问作者Robert Lucas
相关产品推荐
相关产品推荐

