使用带有std :: condition_variable_any的伪假锁是否安全?

时间:2018-05-04 00:30:38

标签: c++ c++11 mutex

我正在寻找的东西就像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的意外行为的潜在风险?

1 个答案:

答案 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来电后继续执行。

必须使用真正的锁来保证条件变量与实际数据/感兴趣的状态一起原子地改变。