如果我有以下代码:
#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搜索,称为写偏置或写优先锁)。使用boost有一个简单的方法吗?或者我需要自己编写吗?
答案 0 :(得分:2)
请注意,我不会对win32实现发表评论,因为它涉及的方式更多,我没有时间详细介绍它。话虽如此,它的接口与pthread实现相同,这意味着以下答案应该同样有效。
v1.51.0中boost :: shared_mutex的pthread实现的相关部分:
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
)或另一个线程拥有写锁定({{1),while循环就不会终止}})。这基本上为您提供了通常的互斥保障。
对于死锁,只要获得写锁定保证解锁,读锁就会一直返回。至于写锁定,只要读取锁定和写入锁定始终保证解锁,就可以保证返回。
如果您想知道,state.exclusive
互斥锁用于确保不会同时调用这些函数中的任何一个。我不打算通过解锁功能,因为他们有更多的参与。你可以随意查看它们,毕竟你有源(state_change
):)
总而言之,这几乎是一本教科书实施,它们已在各种场景中得到广泛测试(boost/thread/pthread/shared_mutex.hpp
并在整个行业中得到广泛使用)。我不会太担心,只要你习惯性地使用它们(没有递归锁定并且总是使用RAII助手锁定)。如果您仍然不相信实现,那么您可以编写一个随机测试,模拟您担心的任何测试用例,让它在数百个线程上运行一夜。这通常是解决僵局的好方法。
现在为什么在请求写锁定后会看到获取读锁?很难说没有看到你正在使用的诊断代码。有可能是在完成print语句(或任何你正在使用的语句)之后以及在写入线程中获取state_change锁之前获取读锁定。