我试图用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
。
我试图打开另一位母亲'线程供读者照顾
获取和释放互斥锁,但在此过程中我迷失了方向。
如果有一种优雅的方法可以克服这个问题(线程可能会尝试以优雅的方式发布一个从未获得过的互斥锁),我很乐意听到!
答案 0 :(得分:4)
如果读者正在进行中,您可以使用条件变量暂停编写器,而不是使用单独的锁。
// --- 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
实现。