我正在尝试查找(或实现)支持低优先级编写器的读取器/写入器锁,但是在研究任何现有解决方案方面都没有成功。
我对低优先级作家的意思是:“将会对即将到来的读者或普通作家产生影响。”
如果有一个恒定的读取器流,肯定会导致饥饿,但这可以通过定时锁定变量(“尝试定时低优先级写入器锁定”然后在超时时切换到正常锁定)或通过更改来解决读者的发布方式(可能会定期暂停读取短窗口)。
如果有任何文献描述这些方面的内容,我还没有找到它。
如果有一个已知的(正确!)解决方案利用常规锁定,我将不胜感激。
答案 0 :(得分:3)
我不知道任何100%喜欢你的提议,但有一些现有的接口很接近:
许多现有的软件锁API都有一个“try lock”界面,比如UN * X系统上的pthread_rwlock_trywrlock()
。这些都是无等待的,如果没有人拥有它也不会获得锁定,也不会等待它。
您通常使用此旋转来锁定,和/或人为延迟尝试代码(退出)。即有类似的代码:
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)
,可用于测试当前线程是否是锁上唯一没有写入器等待的读取器,如果是,则将锁升级为exclusive / write,即你' d代码如:
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,尝试升级。这个过程再次变得旋转。
此外,许多UNIX系统至少实际按照调度优先级执行服务员唤醒;因此,在尝试普通等待wrlock()
呼叫之前,您必须将线程置于最低优先级(如果必要的话,人为地);根据调度程序的工作原理,当你的线程在等待时,其他人想要相同的writelock将在此之前得到它。虽然在多处理器/核心系统上不一定能得到保证......
最后,SymbianOS(Symbian ^ 3版本)有一个RRWlock
类,可以优先考虑读者而不是作者,因此如果有读者等待/进入,它会故意使作者挨饿。再次,不是完全是你想要的行为,因为它会影响给定锁定上的所有作者,而不仅仅是特定的作者。
我担心你必须编写自己的优先锁定,并有两个写入唤醒队列。
答案 1 :(得分:1)
这里您正在查看的是读写器之间的优先级,因此低优先级的读写器总是给高优先级的读写器一个机会。这显然会导致低优先级作家的饥饿,因为它的慷慨大方。
这可以在两个不同的级别上实现: 1.从应用程序方面: 这是一种通常的方法,因为通常互斥锁不带偏见。 在线程争夺锁定之前,应用程序逻辑本身应确定哪个线程具有更高的优先级,并允许该线程进行锁定。 这通常是针对特定应用的:
->任务执行者方法: executeer线程仅根据优先级执行可用任务。 它在执行者级别解决基于优先级的执行,但是在该级别之上会弹出相同的问题。这可以用作基于FIFO的长互斥体实现。这也需要解决饥饿问题。
答案 2 :(得分:0)
在我的头顶,你想要这样的东西:
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()应该可行。