提问人:Serge Rogatch 提问时间:3/17/2023 最后编辑:cafce25Serge Rogatch 更新时间:3/17/2023 访问量:245
如何按值将变量传递给另一个线程?
How to pass a variable by value to another thread?
问:
我需要在 Rust 中启动多个线程,每个线程都接收其工作 ID(包括 0 到 31 之间的整数)。如何在 Rust 中做到这一点?
这是我尝试过的:
struct PtrWrapper(*const u8);
unsafe impl Sync for PtrWrapper {}
unsafe impl Send for PtrWrapper {}
// ...
let data = &mmap[begin_offset..end_offset];
let n_workers = 32;
let total_bytes = data.len();
let bytes_per_worker = (total_bytes + n_workers - 1) / n_workers;
let page_size = 512;
let data_ptr = PtrWrapper(data.as_ptr());
if bytes_per_worker >= page_size {
thread::scope(|scope| {
for i in 0..n_workers {
scope.spawn(|| {
let _ = &data_ptr;
let i_first = bytes_per_worker * i;
let i_limit = cmp::min(total_bytes, bytes_per_worker * (i+1));
for j in (i_first..i_limit).step_by(page_size) {
unsafe {
std::ptr::read_volatile(data_ptr.0.offset(j.try_into().unwrap()));
}
}
});
}
});
}
这给出了一个编译错误:
error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function
--> src/lib.rs:477:41
|
475 | thread::scope(|scope| {
| ----- has type `&'1 Scope<'1, '_>`
476 | for i in 0..n_workers {
477 | scope.spawn(|| {
| ^^ may outlive borrowed value `i`
478 | let _ = &data_ptr;
479 | let i_first = bytes_per_worker * i;
| - `i` is borrowed here
|
note: function requires argument type to outlive `'1`
--> src/lib.rs:477:29
|
477 | / ... scope.spawn(|| {
478 | | ... let _ = &data_ptr;
479 | | ... let i_first = bytes_per_worker * i;
480 | | ... let i_limit = cmp::min(total_bytes, bytes_per_worker * (i+1));
... |
485 | | ... }
486 | | ... });
| |________________________^
help: to force the closure to take ownership of `i` (and any other referenced variables), use the `move` keyword
|
477 | scope.spawn(move || {
| ++++
For more information about this error, try `rustc --explain E0373`.
error: could not compile `safetensors-python` due to previous error
我把其他变量移到了范围之外,这样 Rust 就知道对它们的引用会比线程更长。但是,我可以用变量做什么?i
答:
1赞
cafce25
3/17/2023
#1
只是添加可能对您不起作用,因为闭包内部的唯一正确用途是编译器足够“聪明”,只能尝试将该部分移动到闭包中,这导致它尝试移动不允许的裸,因为指针没有实现,也可以通过提前引用并添加到闭包中来修复它:move
data_ptr
data_ptr.0
*const u8
Send
Sync
data_ptr
move
// …
let data_ptr = PtrWrapper(data.as_ptr());
let data_ptr = &data_ptr;
if bytes_per_worker >= page_size {
std::thread::scope(|scope| {
for i in 0..n_workers {
scope.spawn(move || {
let i_first = bytes_per_worker * i;
let i_limit = total_bytes.min(bytes_per_worker * (i+1));
for j in (i_first..i_limit).step_by(page_size) {
unsafe {
std::ptr::read_volatile(data_ptr.0.offset(j.try_into().unwrap()));
}
}
});
}
});
}
评论
move
scope.spawn
move
move
隐式复制实现的值,其中包括引用。如果我错了,请纠正我,但 AFAICT 因此是唯一未实现的类型,它被您的闭包捕获。如果可以作为参考,也许会起作用?Copy
PointerWrapper
data_ptr
Copy
data_ptr
move
move
Copy
Move
spawn
Arc
PtrWrapper
let _ = &data_ptr;