2012-10-10 29 views
1

如果我有以下代码:是否有增强功能以​​允许写偏向锁定?

#include <boost/date_time.hpp> 
#include <boost/thread.hpp> 

boost::shared_mutex g_sharedMutex; 

void reader() 
{ 
    boost::shared_lock<boost::shared_mutex> lock(g_sharedMutex); 
    boost::this_thread::sleep(boost::posix_time::seconds(10)); 
} 

void makeReaders() 
{ 
    while (1) 
    { 
     boost::thread ar(reader); 
     boost::this_thread::sleep(boost::posix_time::seconds(3)); 
    } 
} 

boost::thread mr(makeReaders); 
boost::this_thread::sleep(boost::posix_time::seconds(5)); 
boost::unique_lock<boost::shared_mutex> lock(g_sharedMutex); 

... 

独特的锁将永远不会被收购,因为总有一些将是读者。我想要一个unique_lock,当它开始等待时,阻止任何新的读锁访问互斥锁(称为基于我的wiki搜索的写偏好或写首选锁)。有没有简单的方法来做到这一点与提升?或者我需要写我自己的?

+0

您是否确认写入锁定永远不会被获取?如果是这样,在什么操作系统?我正在查看pthread实现,它应该优先考虑写入锁定。我并不完全确定win32实现是怎么做的。 –

+0

我没有真正验证这种情况 - 我确实在获得写入锁定之后获取新的读取锁定,这看起来像是一个死锁的秘诀。我正在寻找一个保证,假设所有的读锁最终都会被释放,写锁将被快速获得,并且不会由于新的读锁而延迟。 – Rollie

回答

2

请注意,我不会评论win32的实现,因为它涉及更多的方式,我没有时间详细介绍它。这就是说,它的接口与pthread实现相同,这意味着下面的答案应该同样有效。

的并行线程执行的boost :: shared_mutex作为v1.51.0的相关作品:

void lock_shared() 
{ 
    boost::this_thread::disable_interruption do_not_disturb; 
    boost::mutex::scoped_lock lk(state_change); 

    while(state.exclusive || state.exclusive_waiting_blocked) 
    { 
     shared_cond.wait(lk); 
    } 
    ++state.shared_count; 
} 

void lock() 
{ 
    boost::this_thread::disable_interruption do_not_disturb; 
    boost::mutex::scoped_lock lk(state_change); 

    while(state.shared_count || state.exclusive) 
    { 
     state.exclusive_waiting_blocked=true; 
     exclusive_cond.wait(lk); 
    } 
    state.exclusive=true; 
} 

while循环条件是你最相关的部分。对于lock_shared函数(读锁),只要有一个线程试图获取锁(state.exclusive_waiting_blocked)或已经拥有(state.exclusive),则注意while循环将不会终止。这基本上意味着写入锁定优先于读取锁定。

对于锁定函数(写入锁定),只要至少有一个当前拥有读取锁定的线程(state.shared_count)或另一个线程拥有写入锁定(state.exclusive),while循环就不会终止。这基本上给你通常的互斥保证。

至于死锁,那么只要写入锁定被获取后保证解锁,读取锁定就会一直返回。至于写入锁定,只要读取锁定和写入锁定始终保证一旦获得解锁,就保证返回。

如果您想知道,state_change互斥量用于确保没有对这些函数中的任何一个函数的并发调用。我不打算通过解锁功能,因为他们有更多的参与。随意看看他们自己,你有源(boost/thread/pthread/shared_mutex.hpp):)

总之,这几乎是一个教科书的实施,他们已经广泛的测试在广泛的场景(libs/thread/test/test_shared_mutex.cpp并在整个行业大量使用)。我不会太担心,只要你习惯性地使用它们(没有递归锁定,并且总是使用RAII助手来锁定)。如果你仍然不相信实现,那么你可以编写一个随机测试,模拟你担心的任何测试案例,并让它在数百个线程上运行。这通常是梳理僵局的好方法。

现在为什么你会看到在请求写入锁定之后获取读取锁定?很难说没有看到您正在使用的诊断代码。读取锁可能在您的打印语句(或您正在使用的任何内容)完成之后并且在写入线程中获取state_change锁之前获取。

+0

只是一个无关紧要的迂回笔记。读锁实际上不保证总是返回。如果线程没有停止尝试获取写入锁定,则读取锁定永远不会返回,因为写入锁定始终优先于读取锁定。如果你遇到这个问题,那么通用的shared_lock实现可能不会削减它。哦,你也有更多更大的问题担心:) –

+0

所以你说unique_lock是写偏见像上面的'lock()'方法?使用输出更新代码 - 我很确定我在适用的shared_lock之前访问了unique_lock。同样在你的上面的例子中,它对第一个作者是写偏见的,但是看起来第二个作者将争夺state_change锁的读线程,并且在这种情况下可能击败了作者。 – Rollie

+0

好吧我理智地检查了一下我的测试...在我的主线程的实际测试中,我创建了一个执行'wait(2)'的读线程; shared_lock(gLock);',而主线程在创建该线程后立即进入unique_lock。我认为主线程会在2秒内执行,但我显然是错误的!我实际上写了自己的锁,非常类似于上面的内容,直到我能说服我的团队采用boost ... – Rollie