【问题标题】:Choice of semaphores, mutexes and condition variables信号量、互斥量和条件变量的选择
【发布时间】:2015-10-18 01:57:27
【问题描述】:

我有一个生产者线程和一个消费者线程,生产者是实时的并且对确定性敏感。

因此,我决定使用无锁 fifo 队列将处理从生产者线程提升到消费者线程。目标是让消费者既响应又避免忙等待,同时永远不会延迟生产者不确定的时间;因此任何分配/锁定(和内核条目,我想?)等都是完全不可能的。

我已经实现了这种模式,它似乎运行良好,但是我不确定为什么需要互斥锁:

std::mutex m;
std::condition_variable cv;

void consumer()
{
    std::unique_lock<std::mutex> lock(m);
    while (1)
    {
        cv.wait(lock);
        // process consumation...
    }
}

void producer()
{
    while (1)
    {
        // produce and post..
        cv.notify_one();
    }
}

其他规范示例似乎也将互斥锁锁定在生产者中,为什么?我的数据通信已经是线程安全的,所以不需要它。另外,这是否容易丢失信号?

在研究这个时,我偶然发现了似乎明确用于这种情况的信号量。与这个系统相比有什么好处?我目前更喜欢我的解决方案,因为它是标准库的一部分。

【问题讨论】:

  • 与丢失信号完全相反,这也容易受到虚假唤醒的影响。不要忘记,条件变量不是“状态”;它们只是通信状态已更改的信号机制。状态在 you 提供的单独数据存储变量中进行管理,最重要的是,you 使用 mutex-cv 配对的互斥锁进行保护。该检查以及对状态变量的任何修改,仅在互斥体锁定时进行。
  • 我考虑了虚假唤醒,但在这种情况下它们没有问题,因为除非有东西存在,否则消费者本身永远不会成功弹出队列,因此它将直接再次进入睡眠状态(?)。我可以添加一个等待检查,但我认为它是多余的。如前所述,作为队列的 state 是并发线程安全的,所以我不明白为什么需要使用互斥锁来保护它。但是你措辞的方式,你似乎说这很容易丢失信号。怎么会这样?
  • notify_one 发生并且cvar 上没有活跃的服务员时,我提到的错过的信号(我相信你在质疑)发生。由于您没有提供谓词,因此唯一可以打破该等待的是通知到达某人正在等待。否则会丢失。 see trivial example.
  • 好的,我现在看到了。我想我以某种方式认为信号可能是“未决”的,这样接收信号的唤醒线程就不会再次进入睡眠状态(那一回合)。所以除非我在生产者中使用锁,否则我基本上不能这样做?
  • 我认为你可以在你的情况下这样做,因为你的队列,正如你所说,是无锁的,只需添加一个谓词来检查你的无锁队列等待,当然要确保消费者拥有进入等待之前的互斥锁。您的情况与传统的 cv-mtx 工作略有不同,因为该队列是无锁的。在您的情况下,生产者在附加队列之前不需要锁定互斥锁,但在发出cv.notify_one() 之前,他附加到队列之前关键。如果您启动多个消费者,则需要notify_all

标签: c++ multithreading synchronization producer-consumer


【解决方案1】:

信号量条件变量在某种程度上是相似的概念。至少经典的 Counting Semaphores 不能从当前的 c++ 标准库中本地获得。但是这些可以很容易地用 std::condition_variable 控制一个 in-/decremented 整数值替换。

条件变量的std::mutex 是必要的,以防止在更改基础值时出现竞争条件。

【讨论】:

    猜你喜欢
    • 2011-04-20
    • 2017-08-24
    • 2016-08-30
    • 2012-09-01
    • 2015-10-25
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多