C++11 中的读/写多线程
Posted
技术标签:
【中文标题】C++11 中的读/写多线程【英文标题】:readers-/writers multithreading in C++11 【发布时间】:2016-06-06 22:20:35 【问题描述】:我正在尝试使用 std::thread 在 C++ 中实现读者作者解决方案。
我创建了几个在无限循环中运行的读取器线程,在每次读取访问之间暂停一段时间。我试图重新创建 Tanenbaum 的操作系统书中介绍的算法:
rc_mtx.lock(); // lock for incrementing readcount
read_count += 1;
if (read_count == 1) // if this is the first reader
db_mtx.lock(); // then make a lock on the database
rc_mtx.unlock();
cell_value = data_base[cell_number]; // read data from database
rc_mtx.lock();
read_count -= 1; // when finished 'sign this reader off'
if (read_count == 0) // if this was the last one
db_mtx.unlock(); // release the lock on the database mutex
rc_mtx.unlock();
当然,问题在于可能满足成为最后一个读者(因此想要解锁)条件的线程从未获得db_mtx
。
我试图打开另一个'母亲'线程供读者照顾
获取和释放互斥锁,但在此过程中我迷路了。
如果有一种优雅的方式来克服这个问题(线程可能会尝试释放一个从未获得过的互斥锁),我很想听听!
【问题讨论】:
您是正确的,互斥锁的解锁仅限于锁定它的执行线程,否则它是未定义的。我鼓励你用read_count
重新设计这个std::atomic
,这会阻止作者,除非它的0
你想要达到什么样的实际行为?什么与db_mtx
竞争,您到底为什么要颠簸两个(!)互斥锁来加载您从未使用过的单个值?
如果你不能使用 boost::shared_mutex 或 C++14 shared_timed_mutex,你可以拥有这篇论文中列出的大部分实现:open-std.org/jtc1/sc22/wg21/docs/papers/2007/…
@vu1p3n0x 所以 read_count 的行为就像一个信号量?
【参考方案1】:
如果读取器正在进行中,您可以使用条件变量来暂停写入器,而不是使用单独的锁。
// --- read code
rw_mtx.lock(); // will block if there is a write in progress
read_count += 1; // announce intention to read
rw_mtx.unlock();
cell_value = data_base[cell_number];
rw_mtx.lock();
read_count -= 1; // announce intention to read
if (read_count == 0) rw_write_q.notify_one();
rw_mtx.unlock();
// --- write code
std::unique_lock<std::mutex> rw_lock(rw_mtx);
write_count += 1;
rw_write_q.wait(rw_lock, []return read_count == 0;);
data_base[cell_number] = cell_value;
write_count -= 1;
if (write_count > 0) rw_write_q.notify_one();
这个实现有一个公平问题,因为新读者可以在等待的作者面前切入。一个完全公平的实现可能会涉及一个适当的队列,它允许新读者在等待的作者之后等待,而新的作者在任何等待的读者之后等待。
在 C++14 中,您可以使用 shared_timed_mutex
代替 mutex
来实现多读/单写访问。
// --- read code
std::shared_lock<std::shared_timed_mutex> read_lock(rw_mtx);
cell_value = data_base[cell_number];
// --- write code
std::unique_lock<std::shared_timed_mutex> write_lock(rw_mtx);
data_base[cell_number] = cell_value;
在下一个 C++ 标准(可能是 C++17)中可能会有一个简单的 shared_mutex
实现。
【讨论】:
谢谢!我不知道这种互斥锁。 unique_lock / shared_lock 构造函数是否负责获取 rw_mutex 还是我必须调用如下函数:lock() / unlock() ? 是的。*_lock
助手为您执行 RAII 锁定/解锁。如果要手动更改锁定状态,可以read_lock.unlock()
。以上是关于C++11 中的读/写多线程的主要内容,如果未能解决你的问题,请参考以下文章
利用requestbeautifulsoupxml写多线程爬虫