C ++中条件变量的常见用途是什么?

时间:2010-03-19 09:45:20

标签: c++ multithreading condition-variable

我正在尝试了解条件变量。我想知道使用条件变量的常见情况。

一个例子是阻塞队列,其中两个线程访问队列 - 生产者线程将项目推入队列,而消费者线程从队列中弹出一个项目。如果队列为空,则消费者线程正在等待,直到生产者线程发送信号为止。

您需要使用条件变量的其他设计情况是什么?

我更喜欢基于经验的示例,例如真实应用程序中的示例。

5 个答案:

答案 0 :(得分:2)

条件变量的一个用途是比一个消息队列更复杂,是“共享锁”,其中不同的线程正在等待具有相同基本性质的微妙不同条件。例如,您有一个(非常简单,简化)的Web缓存。缓存中的每个条目都有三种可能的状态:不存在,IN_PROGRESS,COMPLETE。

getURL:
    lock the cache
    three cases for the key:
        not present:
            add it (IN_PROGRESS)
            release the lock
            fetch the URL
            take the lock
            update to COMPLETE and store the data
            broadcast the condition variable
            goto COMPLETE
        COMPLETE:
            release the lock and return the data
        IN_PROGRESS:
            while (still IN_PROGRESS):
                wait on the condition variable
            goto COMPLETE

我实际上在没有调度程序帮助的情况下使用该模式来实现POSIX函数pthread_once的变体。我无法使用每个once_control的信号量或锁定,只是在锁定下进行初始化的原因是该函数不允许失败,once_control只进行了简单的初始化。就此而言,pthread_once本身没有定义的错误代码,因此将其实现为可能失败并不会给调用者带来任何好的选择......

当然,对于这种模式,你必须要小心缩放。每次完成任何初始化时,每个等待的线程都会唤醒以获取锁定。因此,当您设计系统时,您会非常仔细地考虑分片,然后在您看到经过验证的性能问题之前,决定不做任何事情来实际实施它。

答案 1 :(得分:1)

除了消费者 - 生产者模型之外,您已经提到的一个例子是barrier synchronization中的用法。当线程进入屏障时,如果还有其他线程需要进入屏障,那么它们会等待条件变量。进入屏障的最后一个线程表示该情况。

答案 2 :(得分:0)

我用它来发送同步消息,其中添加了一个sync-object 同步对象由一个带有“ready”布尔值的条件变量组成 在syncMsg :: send()函数中,有一个sync-> wait(),在syncMsg :: handle()函数中,有一个sync-> go()。

应该明智地使用,因为可能存在死锁。

答案 3 :(得分:0)

我使用条件变量而不是容易出错的Win32事件对象。使用condvars,您不必担心虚假信号。等待多个事件发生也更容易。

Condvars也可以替换信号量,因为它们更通用。

答案 4 :(得分:0)

我知道这不是很有帮助,但是每当我想要一个线程等待事情发生时,我就会使用条件变量,或者只是等到事情发生。

我使用条件变量的一个非常常见的模式是后台线程,它每隔几分钟就会唤醒一次,然后再进入休眠状态。在关闭时,主线程通知后台线程完成,然后加入完成。后台线程在超时条件下等待,以执行其休眠。

后台线程遵循这个基本逻辑

void threadFunction() {
    initialisation();

    while(! shutdown()) {
        backgroundTask();

        shutdown_condition_wait(timeout_value);
    }

    cleanup();
}

这样可以让后台线程快速,优雅地关闭。

如果我有许多这样的线程,主函数会发出每个关闭信号,然后在下一个之后加入每个线程。这使得每个线程组件可以并行关闭。