我有一个多线程应用程序,必须经常读取一些数据,偶尔会更新数据。现在,互斥锁可以保持对数据安全的访问,但是它很昂贵,因为我希望多个线程能够同时读取,并且只在需要更新时将其锁定(更新线程可以等待其他线程完成)
我认为这是boost::shared_mutex
应该做的事情,但我不清楚如何使用它,并且没有找到明确的例子。
有没有人有一个我可以用来开始的简单例子?
答案 0 :(得分:161)
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
}
另请注意,与shared_lock不同,只有一个线程可以同时获取upgrade_lock,即使它没有升级(当我遇到它时,我认为这很尴尬)。所以,如果你的所有读者都是有条件的作家,你需要找到另一种解决方案。
答案 1 :(得分:98)
看起来你会做这样的事情:
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
}
答案 2 :(得分:44)
您可以使用boost来创建读写锁:
#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;
Lock myLock;
void ReadFunction()
{
ReadLock r_lock(myLock);
//Do reader stuff
}
void WriteFunction()
{
WriteLock w_lock(myLock);
//Do writer stuff
}
答案 3 :(得分:17)
只是为了添加更多经验信息,我一直在调查可升级锁的整个问题,Example for boost shared_mutex (multiple reads/one write)?是一个很好的答案,添加重要信息,即只有一个线程可以拥有upgrade_lock,即使它没有升级,这很重要,因为这意味着您无法在不释放共享锁的情况下从共享锁升级到唯一锁。 (这已在别处讨论,但最有趣的主题是http://thread.gmane.org/gmane.comp.lib.boost.devel/214394)
但是我确实发现等待升级到锁定的线程(即需要等待所有读取器释放共享锁定)和写入等待同一事物的锁定(即unique_lock)之间的重要(未记录)差异)。
正在等待shared_mutex上的unique_lock的线程阻止任何新的读者进入,他们必须等待写入者请求。这可以确保读者不会让作家们挨饿(但我相信作家会让读者们挨饿)。
正在等待upgradeable_lock升级的线程允许其他线程获得共享锁,因此如果读者非常频繁,这个线程可能会被饿死。
这是一个需要考虑的重要问题,可能应该记录在案。
答案 4 :(得分:2)
使用计数等于读者数量的信号量。让每个读者对信号量进行一次计数以便阅读,这样他们就可以同时阅读。然后让作者在写作之前记录所有信号量计数。这会导致编写器等待所有读取完成,然后在写入时阻止读取。
答案 5 :(得分:2)
吉姆莫里斯的回应非常好,我偶然发现了这件事,我花了一些时间来思考。下面是一些简单的代码,显示在为unique_lock boost(版本1.54)提交“请求”后,阻止所有shared_lock请求。这非常有趣,因为在我看来,如果我们想要写优先级或没有优先级,则在unique_lock和upgradeable_lock之间进行选择。
另外(1)吉姆莫里斯的帖子似乎与此相矛盾: Boost shared_lock. Read preferred?
#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();
}