2011-02-22 59 views
4

我试图找到(或实现)支持低优先级编写器的读/写锁,但在研究任何现有解决方案时都未能成功。支持低优先级编写器的读写器锁

我认为低优先级作家的意思是:“将顺利地排在新读者或正常作家身上”。

肯定会导致饥饿,如果有读者络绎不绝,但是这可以解决或者与定时锁变种(“试试定时低优先级的作家锁”,然后切换到上超时正常锁)或改变读者的阅读方式(可能会周期性地暂停阅读短视窗)。

如果有任何文献描述沿着这些线的东西,我还没有找到它。

如果有一个已知的(正确!)解决方案利用常规锁,我希望能得到一个描述。

+0

我很想知道现有的实现,但如果没有,我可以想到的最简单的方法是为低优先级查询创建一个单独的队列,并定期合并到主队列中。它与你提到的定时锁并没有什么不同,只是即使队列为空也会有延迟 - 解决这个问题的一种方法是在需要时添加一个“空队列”事件。 –

回答

3

我什么都不知道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类,它可以优先考虑读者而不是写作者,这样如果有的话读者是否在等待/进入。再次,不完全是您想要的行为,因为它会影响给定锁上的所有作者,而不仅仅是特定的锁。

恐怕你不得不编写自己的优先锁,有两个编写器唤醒队列。

+0

感谢您的详细回复。你的一些想法(延迟旋转)在我最初的想法中,尽管我不知道你的许多例子。 – mmocny

+0

请参阅http://home.roadrunner.com/~hinnant/mutexes/locking.html以获取在C++中实现读/写锁的一些开源代码。不幸的是,这个链接也没有解决原始问题。但它确实解决了与此答案中提出的问题非常相似的问题。这个实现中的读/写优先级是“公平的”。 –

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()应该是可行的。

+0

糟糕...忘了顶部的关键writers.push(...)。 – mcmcc