我的 Rust 代码用于RwLock
在多个线程中处理数据。每个线程在使用锁时填充一个公共存储read
(例如填充一个数据库,但我的情况有点不同)。最终,公共存储空间将被填满。我需要暂停所有处理,重新分配存储空间(例如从云中分配更多磁盘空间),然后继续。
// psudo-code
fn thread_worker(tasks) {
let lock = rwlock.read().unwrap();
for task in tasks {
// please ignore out_of_space check race condition
// it's here just to explain the question
if out_of_space {
drop(lock);
let write_lock = rwlock.write().unwrap();
// get more storage
drop(write_lock);
lock = rwlock.read().unwrap();
}
// handle task WITHOUT getting a read lock on every pass
// getting a lock is far costlier than actual task processing
}
drop(lock);
}
由于所有线程将在大约同一时间快速耗尽空间,因此它们都可以释放read
锁,并获得一个write
. 第一个获得write
锁的线程将解决存储问题。但是现在我有一个可能的临时死锁情况——所有其他线程也在等待write
锁,即使它们不再需要它。
所以这种情况有可能发生:给定 3 个线程都在等待write
,第一个线程得到write
,修复问题,释放write
,并等待read
。第二个进入write
但很快跳过,因为问题已经修复并发布。第 1 个和第 2 个线程将进入read
并继续处理,但第 3 个线程仍在等待write
并将等待很长时间,直到前两个线程空间不足或完成所有工作。
鉴于所有线程正在等待write
,我如何在第一个线程完成工作后,但在它释放write
它已经获得的锁之前“中止”所有其他线程的等待?
我看到有一个poisoning
功能,但它是为恐慌而设计的,并且在生产中重用它似乎是错误的并且很难正确完成。Rust 开发人员也在考虑删除它。
PS 每次循环迭代本质上是一个data[index] = value
赋值,这里data
是一个被许多线程共享的巨大的 memmap。所有线程都在index
缓慢增长,因此最终所有线程都用完了 memmap 大小。发生这种情况时,memmap 被销毁,文件重新分配,并创建一个新的 memmap。因此,不可能在每次循环迭代时都获得读锁。