我目前正在使用boost库实现读/写锁,而不使用shared_lock和unique_lock。我已经阅读了一些相关的问题(例如,How would a readers/writer lock be implemented in C++11?),但我仍然希望优化实施。
这是我的代码:
enum LockType { NO_LOCK, READ_LOCK, WRITE_LOCK, INC_LOCK };
boost::mutex mutex_;
boost::condition condition_;
LockType lock_;
size_t owner_count_;
void AcquireReadLock() {
mutex_.lock();
while (lock_ != NO_LOCK && lock_ != READ_LOCK){
condition_.wait(mutex_);
}
// if there is no lock, then acquire read lock.
if (lock_ == NO_LOCK) {
lock_ = READ_LOCK;
++owner_count_;
mutex_.unlock();
return;
}
else {
// if there is read lock, then still acquire read lock.
assert(lock_ == READ_LOCK);
++owner_count_;
mutex_.unlock();
return;
}
}
void AcquireWriteLock() {
mutex_.lock();
while (lock_ != NO_LOCK){
condition_.wait(mutex_);
}
// if there is no lock, then acquire write lock.
assert(lock_ == NO_LOCK);
lock_ = WRITE_LOCK;
mutex_.unlock();
return;
}
void ReleaseReadLock() {
mutex_.lock();
--owner_count_;
if (owner_count_ == 0) {
lock_ = NO_LOCK;
}
mutex_.unlock();
// is it correct to use notify_all?
condition_.notify_all();
}
void ReleaseWriteLock() {
mutex_.lock();
lock_ = NO_LOCK;
mutex_.unlock();
// is it correct to use notify_all?
condition_.notify_all();
}
问题是:
释放锁时是否应该使用notify_all?根据该文档,一旦线程得到通知,它将重新获取锁。如果使用notify_all,则多个线程可以重新获取相同的锁。那会发生什么?在检查条件之前线程是否会获得锁定(即,锁定_!= NO_LOCK&& lock _!= READ_LOCK)?
如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法?
提前感谢您的帮助!
答案 0 :(得分:1)
- 释放锁时是否应该使用notify_all?根据该文档,一旦线程得到通知,它将重新获取锁。如果使用notify_all,则多个线程可以重新获取相同的锁。那会发生什么?在检查条件之前线程是否会获得锁定(即,锁定_!= NO_LOCK&& lock _!= READ_LOCK)?
醇>
是的,你应该在释放锁时使用notify_all。所有等待mutex_的condition_将被逐个唤醒,因为它们必须首先锁定mutex_(这是在condition_ wait操作内部完成的。)
- 我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法?
醇>
必须通知所有等待mutex_的线程,因为某些写入线程可能正在等待释放读锁定。
我希望这会对你有所帮助!
答案 1 :(得分:0)
如果使用notify_all,则多个线程可以重新获取相同的锁。
没有。每个通知的帖子都会竞争获取锁定获取,与mutex_.lock()
的方式相同。即使使用 notify_all ,最多只有一个线程可以执行关键部分的代码。因此,使用notify_all是完全正确的。
- 我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法?
醇>
由于read永远不会阻塞读取,因此没有读取线程可以wait()
其他读取线程。因此,即使您当前的代码ReleaseReadLock()
也只能通知写线程。
因此,在ReleaseReadLock()
中你可以安全地使用notify()
代替notify_all
:没有理由唤醒所有写线程,因为只有其中一个可以获得你的r / w锁定
至于其他优化,你应该更好地修复这个答案中列出的人工制品:https://stackoverflow.com/a/12657243/3440745