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 中的读/写多线程的主要内容,如果未能解决你的问题,请参考以下文章

22Java并发性和多线程-Java中的读/写锁

利用requestbeautifulsoupxml写多线程爬虫

[多线程]C++11多线程用法整理

多线程中的锁机制

C++11多线程中的detach()join()joinable()

详解c++11多线程