C++中读取写锁定实现
Read Write lock implementation in C++
我正在尝试使用读/写锁定C++使用shared_mutex
typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > WriteLock;
typedef boost::shared_lock< Lock > ReadLock;
class Test {
Lock lock;
WriteLock writeLock;
ReadLock readLock;
Test() : writeLock(lock), readLock(lock) {}
readFn1() {
readLock.lock();
/*
Some Code
*/
readLock.unlock();
}
readFn2() {
readLock.lock();
/*
Some Code
*/
readLock.unlock();
}
writeFn1() {
writeLock.lock();
/*
Some Code
*/
writeLock.unlock();
}
writeFn2() {
writeLock.lock();
/*
Some Code
*/
writeLock.unlock();
}
}
代码似乎工作正常,但我有一些概念问题。
问题 1.我已经看到了在 http://en.cppreference.com/w/cpp/thread/shared_mutex/lock 上使用unique_lock和shared_lock的建议,但我不明白为什么shared_mutex已经支持锁定和lock_shared方法?
问题 2.此代码是否可能导致写入不足?如果是,那么我怎样才能避免饥饿?
问题 3.有没有其他锁定类可以尝试实现读写锁定?
Q1:使用互斥包装器
建议使用包装器对象而不是直接管理互斥锁,以避免代码中断且互斥锁未释放的不幸情况,从而使其永久锁定。
这就是RAII的原则。
但这仅在您的 ReadLock 或 WriteLock 是使用它的函数的本地时才有效。
例:
readFn1() {
boost::unique_lock< Lock > rl(lock);
/*
Some Code
==> imagine exception is thrown
*/
rl.unlock(); // this is never reached if exception thrown
} // fortunately local object are destroyed automatically in case
// an excpetion makes you leave the function prematurely
在您的代码中,如果其中一个函数被中断,这将不起作用,因为您的 ReadLock WriteLock 对象是 Test 的成员,而不是设置锁的函数的本地。
Q2:写入饥饿
目前还不完全清楚您将如何调用读者和作者,但是是的,存在风险:
- 只要读取器处于活动状态,编写器就会被unique_lock阻止,等待互斥锁在独占模式下可用。
- 但是,只要 wrtier 在等待,新读者就可以获得对共享锁的访问权限,从而导致unique_lock进一步延迟。
如果你想避免饥饿,你必须确保等待的作家确实有机会设定他们的unique_lock。 例如,在您的阅读器中有一些代码来检查编写器是否在设置锁之前等待。
Q3 其他锁定类
不太确定您要查找什么,但我的印象是condition_variable
您可能会感兴趣。但逻辑有点不同。
也许,你也可以通过开箱即用来找到解决方案:也许有一种合适的无锁数据结构,可以通过稍微改变方法来促进读者和作家的共存?
锁的类型是可以的,但不是将它们作为成员函数创建,而是在成员函数中locktype lock(mymutex)
.这样,即使在例外的情况下,它们也会在销毁时释放。
问题 1.我已经看到了在 http://en.cppreference.com/w/cpp/thread/shared_mutex/lock 上使用unique_lock和shared_lock的建议,但我不明白为什么shared_mutex已经支持锁定和lock_shared方法?
可能是因为unique_lock自 c++11 以来就已经存在了,但shared_lock 正在加入 c++17。此外,[可能]unique_lock可以更有效率。这是[创作者]http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html shared_lock的原始理由,我尊重这一点。
问题 2.此代码是否可能导致写入不足?如果是,那么我怎样才能避免饥饿?
是的,绝对。如果您这样做:
while (1)
writeFn1();
您最终可以得到以下时间线:
T1: writeLock.lock()
T2: writeLock.unlock()
T3: writeLock.lock()
T4: writeLock.unlock()
T5: writeLock.lock()
T6: writeLock.unlock()
...
T2-T1
的差异是任意的,基于正在完成的工作量。但是,T3-T2
接近于零。这是另一个线程获取锁的窗口。因为窗口太小了,它可能不会得到它。
为了解决这个问题,最简单的方法是插入一个小睡眠(例如 nanosleep
) 在 T2
和 T3
之间。您可以通过将其添加到writeFn1
底部来执行此操作。
其他方法可能涉及为锁创建队列。如果线程无法获取锁,它会将自身添加到队列中,队列中的第一个线程会在释放锁时获得锁。在 linux 内核中,这是为"排队旋转锁"实现
的问题 3.有没有其他锁定类可以尝试实现读写锁定?
虽然不是一个类,但您可以使用pthread_mutex_lock
和pthread_mutex_unlock
。这些实现递归锁。您可以添加自己的代码来实现等效的 boost::scoped_lock
。您的类可以控制语义。
或者,boost
有自己的锁。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 如何找到锁定Linux futex的C++行
- G锁定铸造到基础上会释放模拟行为
- 使用简单类型列表实现的指数编译时间.为什么
- 共享内存的升压容器是否实现锁定?
- 如何在 x86 处理器上实现"锁定添加"
- MCS 锁定实现的问题
- 我是否需要在 OpenSSL 1.1.0+ 中使用加密锁定函数来实现线程安全?
- 在这种情况下,有什么正确的方法可以实现锁定吗?
- 在动作书中的并发中使用拆分参考计数实现锁定堆栈
- 我的双重检查锁定模式实现是否正确?
- MVCC实现中的无锁定读写器同步
- C++中读取写锁定实现
- 通过双重检查锁定模式实现call_once
- 如何为多线程访问实现类锁定对象
- 问题5.3 QPlainTextEdit实现滚动锁定
- MSVC流实现锁定缓冲区