我在Rust中移植我的C ++国际象棋引擎。我有一个在搜索线程之间共享的大哈希表,在C ++版本中这个表是无锁的;没有用于共享读/写访问的互斥锁。如果您有兴趣,请参阅the theory。
在此代码的Rust版本中,它工作正常,但使用Mutex
:
let shared_hash = Arc::new(Mutex::new(new_hash()));
for _ in 0..n_cpu {
println!("start thread");
let my_hash = shared_hash.clone();
thread_pool.push(thread::spawn(move || {
let mut my_hash = my_hash.lock().unwrap();
let mut search_engine = SearchEngine::new();
search_engine.search(&mut myhash);
}));
}
for i in thread_pool {
let _ = i.join();
}
如何在没有互斥锁的线程之间共享表?
答案 0 :(得分:4)
非常简单,实际上:如果底层结构已经Mutex
,则Sync
是不必要的。
在你的情况下,例如原子结构的数组就可以了。你可以找到Rust的可用原子here。
答案 1 :(得分:0)
Data races are undefined behavior。只是说不。
正确的方法是从atomic integers构建你的桌子。它是火箭科学。 You have to decide case by case你care about the order of memory operations多少钱。这会使代码混乱:
// non-atomic array access
table[h] = 0;
// atomic array access
table[h].store(0, Ordering::SeqCst);
但它值得。
不知道性能损失是什么 - 你只需要尝试一下。
答案 2 :(得分:-1)
正如所建议的那样,我编写了KEYUP
来实现FakeMutex
,但并没有真正锁定哈希表:
Sync
我的新代码是:
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Deref, DerefMut};
pub struct FakeMutex<T> {
data: UnsafeCell<T>,
}
pub struct FakeMutexGuard<'a, T: 'a> {
data: &'a mut T,
}
unsafe impl<T> Sync for FakeMutex<T> {}
impl<T> FakeMutex<T> {
pub fn new(user_data: T) -> FakeMutex<T> {
FakeMutex {
data: UnsafeCell::new(user_data),
}
}
pub fn lock(&self) -> FakeMutexGuard<T> {
FakeMutexGuard {
data: unsafe { &mut *self.data.get() },
}
}
}
impl<'a, T> Deref for FakeMutexGuard<'a, T>{
type Target = T;
fn deref<'b>(&'b self) -> &'b T { &*self.data }
}
impl<'a, T> DerefMut for FakeMutexGuard<'a, T>{
fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}
这解决了我的问题。