我试图找到(或实现)支持低优先级编写器的读/写锁,但在研究任何现有解决方案时都未能成功。支持低优先级编写器的读写器锁
我认为低优先级作家的意思是:“将顺利地排在新读者或正常作家身上”。
肯定会导致饥饿,如果有读者络绎不绝,但是这可以解决或者与定时锁变种(“试试定时低优先级的作家锁”,然后切换到上超时正常锁)或改变读者的阅读方式(可能会周期性地暂停阅读短视窗)。
如果有任何文献描述沿着这些线的东西,我还没有找到它。
如果有一个已知的(正确!)解决方案利用常规锁,我希望能得到一个描述。
我试图找到(或实现)支持低优先级编写器的读/写锁,但在研究任何现有解决方案时都未能成功。支持低优先级编写器的读写器锁
我认为低优先级作家的意思是:“将顺利地排在新读者或正常作家身上”。
肯定会导致饥饿,如果有读者络绎不绝,但是这可以解决或者与定时锁变种(“试试定时低优先级的作家锁”,然后切换到上超时正常锁)或改变读者的阅读方式(可能会周期性地暂停阅读短视窗)。
如果有任何文献描述沿着这些线的东西,我还没有找到它。
如果有一个已知的(正确!)解决方案利用常规锁,我希望能得到一个描述。
我什么都不知道100%像你的建议,但有是接近一些现有的接口:
许多现有的R/W锁的API有一个“尝试锁定”界面,像pthread_rwlock_trywrlock()
在UN * X系统。这些都是免等待的,只有在没有人拥有它的情况下才会获得锁定,也不会等待。
您通常会使用此旋转锁定和/或人为延迟尝试代码(退格)。即有这样的代码:
for (count = 0; count < MAX_SPINS && (locked = trywrlock(lock)); count++);
if (locked) {
delay(some_backoff);
wrlock(lock); /* or try spinning loop above again ? */
}
不幸的是,这不是你所要求的;它迟早会得到锁定,但是由于(可能不必要的)退避,低优先级的作者将在CPU上旋转和/或以延迟的方式得到它。
Solaris内核有一个接口rw_tryupgrade(9f)
,可用于测试是否当前线程是没有作家等待,如果是这样的锁的唯一读者,锁升级为独占/写,也就是你喜欢的代码:
if (!rw_tryenter(lock, RW_WRITER)) {
rw_enter(lock, RW_READER); /* this might wait for a writer */
if (!rw_tryupgrade(lock)) { /* this fails if >1 reader/writer waiting */
/* do what you must to if you couldn't get in immediately */
}
}
这是一个有点接近你问什么,但还是不完全一样 - 如果失败的话,你必须放下readlock,可能回退(等待),reaquire的readlock,尝试升级。这个过程再次相当于旋转。另外,许多UNIX系统至少实际上以调度优先级的顺序执行服务器唤醒;所以你必须在尝试普通之前让你的线程最低优先级(如果必要的话,人为地),等待wrlock()
呼叫;当线程正在等待时,谁想要相同的写锁,在调度程序工作的前提下,它会在它之前得到它。尽管在多处理器/核心系统上不一定能保证...
最后,SymbianOS(Symbian^3版本)有一个RRWlock
类,它可以优先考虑读者而不是写作者,这样如果有的话读者是否在等待/进入。再次,不完全是您想要的行为,因为它会影响给定锁上的所有作者,而不仅仅是特定的锁。
恐怕你不得不编写自己的优先锁,有两个编写器唤醒队列。
感谢您的详细回复。你的一些想法(延迟旋转)在我最初的想法中,尽管我不知道你的许多例子。 – mmocny
请参阅http://home.roadrunner.com/~hinnant/mutexes/locking.html以获取在C++中实现读/写锁的一些开源代码。不幸的是,这个链接也没有解决原始问题。但它确实解决了与此答案中提出的问题非常相似的问题。这个实现中的读/写优先级是“公平的”。 –
关闭我的头顶,你会想是这样的:
class PriorityRWLock
{
int rwcount;
mutex mtx;
condition_variable cv;
priority_queue<writer_info> writers;
};
...和PriorityRWLock :: acquire_write_lock()看起来是这样的:
lock_guard raii(mtx);
do {
if (rwcount==0) // == no read or write locks
{
if (writers.top().thread == thread::self())
{ rwcount = -1; writers.pop_front(); break; } // == exclusive write access
else
{
// wake up the waiting thread(s) and sleep
writers.push(writer_info(thread::self(),priority));
cv.notify_all();
cv.wait(mtx);
}
}
else
{ cv.wait(mtx); } // sleep
} while (true);
..或者接近于此。
它不会过于高效。你真的希望将rwcount存储在atomic_int或类似的地方,但是对condition_variable的需求排除了这一点。
由于可能需要间歇性等待(),所以定时锁定会非常棘手。 try_write_lock()应该是可行的。
糟糕...忘了顶部的关键writers.push(...)。 – mcmcc
我很想知道现有的实现,但如果没有,我可以想到的最简单的方法是为低优先级查询创建一个单独的队列,并定期合并到主队列中。它与你提到的定时锁并没有什么不同,只是即使队列为空也会有延迟 - 解决这个问题的一种方法是在需要时添加一个“空队列”事件。 –