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 搜索,称为偏写锁或写优先锁)。有没有一种简单的方法可以通过 boost 做到这一点?还是我需要自己写?

4

1 回答 1

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)或另一个线程拥有写锁(state.exclusive),while循环就不会终止。这基本上为您提供了通常的互斥保证。

至于死锁,只要保证一旦获得写锁就可以解锁,读锁总是会返回。至于写锁,只要读锁和写锁总是保证一旦获得就解锁就保证返回。

如果您想知道,state_change互斥锁用于确保没有对这些函数中的任何一个的并发调用。我不打算介绍解锁功能,因为它们涉及更多。随意查看它们,毕竟你有来源(boost/thread/pthread/shared_mutex.hpp):)

All in all, this is pretty much a text book implementation and they've been extensively tested in a wide range of scenarios (libs/thread/test/test_shared_mutex.cpp and massive use across the industry). I wouldn't worry too much as long you use them idiomatically (no recursive locking and always lock using the RAII helpers). If you still don't trust the implementation, then you could write a randomized test that simulates whatever test case you're worried about and let it run overnight on hundreds of thread. That's usually a good way to tease out deadlocks.

Now why would you see that a read lock is acquired after a write lock is requested? Difficult to say without seeing the diagnostic code that you're using. Chances are that the read lock is acquired after your print statement (or whatever you're using) is completed and before state_change lock is acquired in the write thread.

于 2012-10-11T01:14:40.330 回答