Reader Writer Lock支持低优先级编写器

时间:2011-02-22 16:48:05

标签: c++ concurrency mutex readerwriterlock

我正在尝试查找(或实现)支持低优先级编写器的读取器/写入器锁,但是在研究任何现有解决方案方面都没有成功。

我对低优先级作家的意思是:“将会对即将到来的读者或普通作家产生影响。”

如果有一个恒定的读取器流,肯定会导致饥饿,但这可以通过定时锁定变量(“尝试定时低优先级写入器锁定”然后在超时时切换到正常锁定)或通过更改来解决读者的发布方式(可能会定期暂停读取短窗口)。

如果有任何文献描述这些方面的内容,我还没有找到它。

如果有一个已知的(正确!)解决方案利用常规锁定,我将不胜感激。

3 个答案:

答案 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的长互斥体实现。这也需要解决饥饿问题。

  1. 写一个有偏见的锁定机制,该机制了解优先级并允许更高优先级的线程锁定。这也需要确保“没有饥饿”。 可以实现互斥量的即兴版本。

答案 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()应该可行。