c++ - 具有条件和无锁通知的可移植事件检查器

标签 c++ events lock-free condition-variable

我需要让实时(音频)线程在事件发生时向另一个后台线程发出信号。后台“检查器”线程将执行一些昂贵的操作。

因此我的限制是:

  • 通知操作必须是无锁的(等待端无此限制)

  • 防止检查器线程浪费 CPU 时间,并在不需要时将其适当休眠,因为事件之间可能相隔几分钟。

  • 代码必须是可移植的(osx、windows、android、ios)。

我想出了一个使用条件变量和条件标志的简单解决方案。当条件变量在检查器线程开始等待之前发出信号时,需要该标志来防止检查器线程等待(可能永远)。

struct EventChecker {

    std::mutex mtx;
    std::condition_variable cv;
    std::atomic<bool> flag;
    bool alive;
    std::thread checkerThread;

    EventChecker() {
        alive = true;
        checkerThread = std::thread([this]() {
            while (alive) {
                std::unique_lock<std::mutex> lock(mtx);
                cv.wait(lock, [this]() { return flag.exchange(false); });
                std::cout << " action! ";
            }
        });
    }

    void notify() {
        flag.store(true);
        cv.notify_one();
    }

    ~EventChecker() {
        alive = false;
        notify();
        checkerThread.join();
    }
};

如果 notify() 发生在标志检查和等待的实际开始之间,此解决方案将死锁(准确地说,检查线程未被唤醒)。如果您认为带条件的 wait 的实现只是:

,那就更清楚了
while (!predicate())
    wait(lock);

通过这个简单的测试,很容易出现死锁(在 macbook 上重现):

int main() {
    for (int i = 0; i < 10000; i++) {
            EventChecker ec;
    }
    return 0;
}

据我了解,如果不在 notify 中锁定 mtx 并在等待端添加解锁以减少保留时间,实际上没有办法使 check+wait 操作原子化,如下所示:

std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this]() { return flag.exchange(false); });
// NB: wait() atomically releases lock and blocks the thread
mtx.unlock();

我错过了什么吗?我是否滥用了 std::condition_variable 并且还有其他更适合我的目的?

最佳答案

对于没有锁的原子check-and-wait,你可以使用futex机制。不幸的是,这种机制不是任何 C/C++ 标准的一部分,它是低级操作系统支持的一部分:

我还没有在 OSX 上找到任何 futex 的类似物,并且不知道它在 ios 上。

关于c++ - 具有条件和无锁通知的可移植事件检查器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49834624/

相关文章:

c++ - 在 CLion 中,仅 header 库 : file "does not belong to any project target, code insight features might not work properly"

C++:如何将任何可迭代类型作为函数参数传递

C++ Cycling 包括(三个类,两个虚拟)

java - 在 C++ 中有类似 Java 的 AtomicStampedReference 的东西吗?

c# - 尝试编写无锁单链表,删除麻烦

c++ 埃拉托色尼筛法我的代码很慢

java - 有没有什么方法可以找出Android智能手机的显示变化事件?

javascript - 所有型号的值相同 -> 收集事件

events - IE10是否支持触摸事件?

c++11 - 从 boost lock free spsc 队列中得到错误的输出