[英]Read Write lock implementation in C++
我正在尝试使用shared_mutex在C ++中使用读/写锁
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();
}
}
该代码似乎工作正常,但我有一些概念性问题。
Q1。 我已经在http://en.cppreference.com/w/cpp/thread/shared_mutex/lock上看到了使用unique_lock和shared_lock的建议,但是我不明白为什么这样,因为shared_mutex已经支持lock和lock_shared方法了?
Q2。 此代码是否有可能导致写饥饿? 如果是,那我该如何避免饥饿呢?
Q3。 我可以尝试实现读写锁定的任何其他锁定类吗?
锁的类型还可以,但是与其在成员函数中创建它们,不如在成员函数内部创建locktype lock(mymutex)
。 这样,即使在例外情况下,它们也可以在破坏时释放。
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。 例如,在您的读者中输入一些代码来检查作家是否在设置锁之前正在等待。
Q3其他锁类
不太确定您要寻找的内容,但我的印象是condition_variable
可能对您很感兴趣。 但是逻辑有些不同。
也许,您还可以通过开箱即用的思维找到解决方案:也许有一个合适的无锁数据结构,可以通过稍微改变方法来促进读者和作家的共存?
Q1。 我已经在http://en.cppreference.com/w/cpp/thread/shared_mutex/lock上看到了使用unique_lock和shared_lock的建议,但是我不明白为什么这样,因为shared_mutex已经支持lock和lock_shared方法了?
可能是因为unique_lock自c ++ 11起就出现了,但是shared_lock随c ++ 17一起提供了。 同样,[可能] unique_lock可以更有效。 这是[创建者] shared_lock的原始原理, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html ,我谨以此为准。
Q2。 此代码是否有可能导致写饥饿? 如果是,那我该如何避免饥饿呢?
是的,一点没错。 如果您这样做:
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
接近零。 这是另一个线程获取锁的窗口。 因为窗口很小,所以可能无法获取。
为了解决这个问题,最简单的方法是在T2
和T3
之间插入一个小睡眠(例如nanosleep
)。 您可以通过将其添加到writeFn1
的底部来完成此writeFn1
。
其他方法可能涉及为锁创建队列。 如果线程无法获取锁,则将其自身添加到队列中,并在释放锁时队列中的第一个线程获取锁。 在linux内核中,这是针对“排队自旋锁”实现的
Q3。 我可以尝试实现读写锁定的任何其他锁定类吗?
虽然不是类,但可以使用pthread_mutex_lock
和pthread_mutex_unlock
。 这些实现递归锁。 您可以添加自己的代码来实现等效于boost::scoped_lock
。 您的课程可以控制语义。
或者, boost
有其自己的锁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.