我正在寻找的东西就像linux内核中的wait_queue_t。我与同步相关的基础数据结构是无锁的,因此不需要保护互斥锁。
为了能够使用std::mutex
阻止等待而必须获得std::condition_variable
似乎会带来不必要的开销。
我知道Linux有futex
,Windows有WaitOnAddress
但我对这里的语言标准更感兴趣。
根据cppreference wiki std::condition_variable_any
可以使用任何自定义Lockable
。
那么,如果我使用虚拟假锁,如下所示:
class FakeLock
{
public:
inline void lock() {}
inline void unlock() {}
inline bool try_lock() { return true; }
};
template<typename WaitLock=FakeLock>
class WaitQueue
{
private:
WaitLock m_lock;
std::condition_variable_any m_cond;
public:
inline void wait()
{
std::unique_lock<WaitLock> lock(m_lock);
m_cond.wait(lock);
}
inline void notify_one()
{
m_cond.notify_one();
}
inline void notify_all()
{
m_cond.notify_all();
}
};
使用linux内核WaitQueue
的方式是否存在使用上述wait_queue_t
的意外行为的潜在风险?
答案 0 :(得分:0)
再次思考这个问题,我想我得到了答案。
给定一个类ERRORLEVEL
,它是一个无锁堆栈。
考虑以下代码:
LockFreeStack
如果不使用实际锁保护wait_queue /条件变量,则两个线程可以按以下顺序执行:
WaitQueue wq;
LockFreeStack<std::string> stack;
std::thread t1([&]() {
while (true) {
// sleep for some time
stack.push(/* random string */); // (1.1)
wq.notify_one(); // (1.2)
}
});
std::thread t2([&]() {
while (true) {
if (stack.empty()) // (2.1)
wq.wait(); // (2.2)
auto str = stack.pop();
// print string
}
});
让线程(2.1)
(1.1)
(1.2)
(2.2)
完全错过t2
的最新更新。 t1
只能在下一次t2
来电后继续执行。
必须使用真正的锁来保证条件变量与实际数据/感兴趣的状态一起原子地改变。