例如升级 share_mutex (多次读/一次写) ?

我有一个多线程应用程序,必须经常读取一些数据,有时这些数据是更新。现在互斥锁保证了对数据的安全访问,但是代价很高,因为我希望多个线程能够同时读取,并且只在需要更新时才锁定它们(更新线程可以等待其他线程完成)。

我认为这是 boost::shared_mutex应该做的,但我不清楚如何使用它,也没有找到一个明确的例子。

有人能举个简单的例子让我开始吗?

106467 次浏览

看起来你会这么做:

boost::shared_mutex _access;
void reader()
{
// get shared access
boost::shared_lock<boost::shared_mutex> lock(_access);


// now we have shared access
}


void writer()
{
// get upgradable access
boost::upgrade_lock<boost::shared_mutex> lock(_access);


// get exclusive access
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
// now we have exclusive access
}

使用计数等于读取器数量的信号量。让每个读者计算一次信号量来读取,这样他们就可以同时读取。然后让写入器在写入之前获取所有的信号量计数。这会导致写入器等待所有读取完成,然后在写入时阻止读取。

1800信息或多或少是正确的,但有一些问题,我想更正。

boost::shared_mutex _access;
void reader()
{
boost::shared_lock< boost::shared_mutex > lock(_access);
// do work here, without anyone having exclusive access
}


void conditional_writer()
{
boost::upgrade_lock< boost::shared_mutex > lock(_access);
// do work here, without anyone having exclusive access


if (something) {
boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
// do work here, but now you have exclusive access
}


// do more work here, without anyone having exclusive access
}


void unconditional_writer()
{
boost::unique_lock< boost::shared_mutex > lock(_access);
// do work here, with exclusive access
}

还有注意,与 share _ lock 不同的是,只有一个线程可以同时获得 update _ lock,即使它没有升级(当我遇到这个问题时,我觉得很尴尬)。因此,如果您的所有读者都是条件作者,那么您需要找到另一个解决方案。

为了补充更多的经验信息,我一直在研究可升级锁的整个问题,而 例如升级 share _ mutex (多次读/一次写) ?是一个很好的答案,它补充了一个重要的信息,即只有一个线程可以有一个 update _ lock,即使它没有升级,这是很重要的,因为它意味着你不能从一个共享锁升级到一个唯一的锁,而不先释放共享锁。(这已经在其他地方讨论过了,但是最有趣的线索在这里 http://thread.gmane.org/gmane.comp.lib.boost.devel/214394)

然而,我确实发现了等待升级到锁(即需要等待所有读取器释放共享锁)的线程和等待同一事物(即惟一锁)的写入器锁之间的一个重要(未记录的)区别。

  1. 正在等待 share _ mutex 上的惟一锁的线程阻止任何新的读取器进入,它们必须等待写入器请求。这样可以确保读者不会饿死作者(不过我相信作者会饿死读者)。

  2. 正在等待升级可升级锁的线程允许其他线程获得共享锁,因此如果读者非常频繁,该线程可能会处于饥饿状态。

这是一个需要考虑的重要问题,也许应该加以记录。

因为 C + + 17(VS2015) ,你可以使用读写锁的标准:

#include <shared_mutex>


typedef std::shared_mutex Lock;
typedef std::unique_lock< Lock > WriteLock;
typedef std::shared_lock< Lock > ReadLock;


Lock myLock;




void ReadFunction()
{
ReadLock r_lock(myLock);
//Do reader stuff
}


void WriteFunction()
{
WriteLock w_lock(myLock);
//Do writer stuff
}

对于旧版本,您可以使用相同的语法升级:

#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>


typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock >  WriteLock;
typedef boost::shared_lock< Lock >  ReadLock;

吉姆 · 莫里斯的回应很棒,我偶然发现了这个,我花了一段时间才弄明白。下面是一些简单的代码,它们显示在提交了一个惟一锁增强(版本1.54)的“请求”之后,阻止所有的共享锁请求。这是非常有趣的,因为在我看来,如果我们想要写优先级或没有优先级的话,可以在惟一锁和可升级锁之间进行选择。

同样(1)在吉姆 · 莫里斯的文章中似乎与此相矛盾: 提升共享 _ lock。首选读取方式?

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


using namespace std;


typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > UniqueLock;
typedef boost::shared_lock< Lock > SharedLock;


Lock tempLock;


void main2() {
cout << "10" << endl;
UniqueLock lock2(tempLock); // (2) queue for a unique lock
cout << "11" << endl;
boost::this_thread::sleep(boost::posix_time::seconds(1));
lock2.unlock();
}


void main() {
cout << "1" << endl;
SharedLock lock1(tempLock); // (1) aquire a shared lock
cout << "2" << endl;
boost::thread tempThread(main2);
cout << "3" << endl;
boost::this_thread::sleep(boost::posix_time::seconds(3));
cout << "4" << endl;
SharedLock lock3(tempLock); // (3) try getting antoher shared lock, deadlock here
cout << "5" << endl;
lock1.unlock();
lock3.unlock();
}