英文:
Circumventing thread safety in rust with mutable pointers
问题
I have a performance critical section of my rust code which I currently try to get faster with unsafe code. In this approach I grantee thread safety manually with barriers and separated index ranges for all threads in the vectors, so I do not want to compiler to check thread safety.
#[derive(Clone, Copy)]
struct CgPtrSet {
a: *const SparseMatrix,
b: *const DenseVector,
x: *mut DenseVector,
d: *mut DenseVector,
r: *mut DenseVector,
z: *mut DenseVector,
accuracy: *mut f64,
iterations: *mut usize,
}
fn cg_barrier_thread_worker(&self, ptrs: CgPtrSet, start: usize, end: usize) {
unsafe {
// ...
}
}
This works well while done in one thread:
self.cg_barrier_thread_worker(ptrs, start, end);
Now I run it in its own thread:
let thread_handle = thread::spawn(|| {
self.cg_barrier_thread_worker(ptrs, start, end);
});
thread_handle.join().unwrap();
That gives me the compiler output:
error[E0277]: `*const sparse_matrix::SparseMatrix` cannot be shared between threads safely
error[E0277]: `*const dense_vector::DenseVector` cannot be shared between threads safely
...and so on for all members of CgPrtSet
I have tried to solve the issue using UnsafeCell with no success. How can I "convince" the compiler that I know my use of the object is thread-safe?
英文:
I have a performance critical section of my rust code which I currently try to get faster with unsafe code. In this approach I grantee thread safety manually with barriers and separated index ranges for all threads in the vectors, so I do not want to compiler to check thread safety.
#[derive(Clone, Copy)]
struct CgPtrSet {
a: *const SparseMatrix,
b: *const DenseVector,
x: *mut DenseVector,
d: *mut DenseVector,
r: *mut DenseVector,
z: *mut DenseVector,
accuracy: *mut f64,
iterations: *mut usize,
}
fn cg_barrier_thread_worker(&self, ptrs: CgPtrSet, start: usize, end: usize) {
unsafe {
...
}
}
This works well while done in one thread:
self.cg_barrier_thread_worker(ptrs, start, end);
Now I run it in its own thread:
let thread_handle = thread::spawn(|| {
self.cg_barrier_thread_worker(ptrs, start, end);
});
thread_handle.join().unwrap();
That get me the compiler output:
error[E0277]: `*const sparse_matrix::SparseMatrix` cannot be shared between threads safely
error[E0277]: `*const dense_vector::DenseVector` cannot be shared between threads safely
...and so on for all members of CgPrtSet
I have tried to solve the issue using UnsafeCell with no success. How can I “convince” the compiler that I know my use of the object is thread save?
答案1
得分: 0
// 让我们制作一个最小的结构示例,其中包含一个指针
struct HoldsRawPtr {
ptr: *const u8,
}
// 通过实现 Send 特性,我们告诉编译器这种类型可以在线程之间传递而不违反安全性。它是否真的安全由我们负责
unsafe impl Send for HoldsRawPtr {}
// Sync 特性告诉编译器`&T`在线程之间共享是安全的
unsafe impl Sync for HoldsRawPtr {}
fn main() {
let ptr = HoldsRawPtr {
ptr: std::ptr::null(),
};
// 现在可以这样做
std::thread::spawn(move || {
// 使用 ptr 做一些操作
let _moved_ptr = ptr;
});
// 这里您可以看到 std::thread::spawn 的签名
pub fn spawn<F, T>(f: F) -> std::thread::JoinHandle<T>
where
// 闭包的发送约束要求所有捕获的值都是可发送的
// 因此,HoldsRawPtr 上不需要 Sync 约束,尽管如果您将其包装在 Arc 中,就需要 Sync 约束
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
unreachable!("...")
}
}
英文:
// lets make minimal example of struct holding a pointer
struct HoldsRawPtr {
ptr: *const u8,
}
// By implementing the Send trait, we tell compiler that this type can be transferred between
// threads without violating safety. Whether it actually is safe is our responsibility
unsafe impl Send for HoldsRawPtr {}
// Sync trait tells compiler that `&T` is safe to share between threads
unsafe impl Sync for HoldsRawPtr {}
fn main() {
let ptr = HoldsRawPtr {
ptr: std::ptr::null(),
};
// This is now possible
std::thread::spawn(move || {
// do something with ptr
let _moved_ptr = ptr;
});
// here you can see signature of std::thread::spawn
pub fn spawn<F, T>(f: F) -> std::thread::JoinHandle<T>
where
// send bound on closure requires that all captures are send
// so we don't need Sync bound on HoldsRawPtr, though if you wrapped it in Arc,
// you would need Sync bound
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
unreachable!("...")
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论