【发布时间】:2020-07-06 02:25:27
【问题描述】:
我正在使用 Rust 中的光线追踪器作为学习语言的一种方式,并且单线程版本运行良好。我想通过多线程来加速它,并且在 C/C++ 中对光线追踪器进行多线程处理相对容易,因为大多数共享的数据都是只读的(写入像素数据时会出现唯一的问题)。但是我在 Rust 及其所有权规则方面遇到了更多麻烦。
我有一个特征 Hittable: Send + Sync 可以在世界上受到影响的不同类型的事物(球体、网格),我将 Send 和 Sync 的实现留空,因为我实际上并不需要的任何一方。然后我有一个Vec<Box<dyn Hittable>> 类型的世界对象的vec。对于实际的多线程,我正在尝试这样的事情:
let pixels_mutex: Arc<Mutex<Vec<Vec<(f64, f64, f64, u32)>>>> = Arc::new(Mutex::new(pixels));
let vec_arc: Arc<Vec<Box<dyn Hittable>>> = Arc::new(vec);
let mut thread_vec: Vec<thread::JoinHandle<()>> = Vec::new();
for _ in 0..NUM_THREADS {
let camera_clone = camera.clone();
thread_vec.push(thread::spawn(move || {
for r in 0..RAYS_PER_THREAD {
if r % THREAD_UPDATE == 0 {
println!("Thread drawing ray {} of {} ({:.2}%)", r, RAYS_PER_THREAD, (r as f64 * 100.) / (RAYS_PER_THREAD as f64));
}
let u: f64 = util::rand();
let v: f64 = util::rand();
let ray = camera_clone.get_ray(u, v);
let res = geometry::thread_safe_cast_ray(&ray, &vec_arc, MAX_DEPTH);
let i = (u * IMAGE_WIDTH as f64).floor() as usize;
let j = (v * IMAGE_HEIGHT as f64).floor() as usize;
util::thread_safe_increment_color(&pixels_mutex, j, i, &res);
}
}));
}
for handle in thread_vec {
handle.join().unwrap();
}
我已经实现了thread_safe_increment_color,这看起来不错,但我会推迟执行thread_safe_cast_ray,直到我让这个循环正常工作。我在这段代码中遇到的问题是每个线程都试图将vec_arc 移动到它的闭包中,这违反了所有权规则。我尝试像使用camera 一样克隆vec_arc,但编译器不会让我这样做,我认为这是因为我的Hittable 特征不需要Copy 或Clone 特征。我实现Hittable 的结构不能简单地derive(Copy, Clone),因为它们包含Box<dyn Material>,其中Material 是表示对象材质的另一个特征。
我认为这会更容易,因为我知道大部分数据(pixels_mutex 除外)都是只读的。如何在我正在创建的线程之间共享vec_arc(就此而言,pixels_mutex)?
【问题讨论】:
-
您应该能够克隆
vec_arc,就像使用camera一样。但是你必须小心克隆指针而不是向量,所以你应该在关闭之前使用let vec_arc = Arc::clone(&vec_arc)。这样可以编译吗? -
vec_arc工作正常,谢谢! -
我现在已经发布了答案。
标签: multithreading rust raytracing