【问题标题】:To Mutex or Not To Mutex?互斥还是不互斥?
【发布时间】:2011-01-06 22:44:51
【问题描述】:

如果我只有一个读取器和一个写入器,我是否需要互斥锁?阅读器从队列中获取下一个命令(food.front())并根据该命令执行任务。命令执行后,它会弹出命令。队列的写入者将命令推送到队列 (food.push())。

我需要互斥体吗?我的读者(消费者)仅在food.size() > 0 时执行。我正在使用阅读器线程和发送线程。

【问题讨论】:

  • 您在上面使用哪个容器?
  • @Timo: queue<unsigned char> food;

标签: c++ windows multithreading mutex


【解决方案1】:

互斥体用于多线程环境。我没有看到您的问题中提到线程,所以我认为不需要互斥锁。

但是,如果我们假设读取器和写入器意味着您有两个线程,则需要使用互斥锁(或其他多线程保护方案)来保护相互数据。

当队列有项目时会发生什么,并且阅读器线程弹出一些东西而写入器线程放置一些东西?灾难!使用互斥锁,您可以确保一次只有一个线程在队列上运行。

另一种方法是无锁线程安全队列。它将使用原子操作来确保数据不会被错误地操作。

【讨论】:

  • @John:啊,我通常不观察标签,我的错。
  • @GManNickG:“无锁线程安全队列”是什么意思。我根据自己的需要建造的?还是STL中有这样的东西?
  • @steffen:我不建议构建一个,它可能很难做好。英特尔的 TBB 和 MSVC 的 PPL 库都有一个,两者的名称都是 concurrent_queue。但是,如果您不需要无锁属性(通常仅在高负载情况下有用的属性),您可以很容易地实现阻塞并发队列:justsoftwaresolutions.co.uk/threading/…
【解决方案2】:

如果读者看到大小大于零,但结构尚未完全更新,会发生什么?

这可以通过非常仔细地对更新进行编码来避免,但是使代码能够抵抗未来篡改更新的方法是使用互斥锁。

【讨论】:

  • 如果我们谈论在多处理器/多核架构上的执行,“非常仔细地对更新进行编码”意味着在正确的位置使用正确的内存屏障,这是一个令人头疼的问题。
【解决方案3】:

假设“作者”和“阅读者”在不同的线程中:

很可能是的:您可以在“写入”事件和“读取”事件之间具有“亚稳态”状态,其中指向结构的指针是一致的。

当然这取决于实现:如果使用 原子操作 来更新指针,那么没有互斥锁可能会很好。

【讨论】:

    【解决方案4】:

    完全取决于实现,如果您有两个不同的线程访问相同的变量,您将需要一个互斥锁。否则,例如,您可能会得到不一致的计数。

    说在写你做++count,在读你做--count并说当前值为2。现在注意这些语句不需要是原子的,++count可能由读取变量count组成,增加它然后再写回来。没有同时执行写入和读取,并说执行写入的第一位被执行(即它加载值 2。然后执行整个读取以递减计数,但另一个线程仍然加载了值 2,它递增并随后写回变量。现在您只是丢失了一个读取操作。

    【讨论】:

      【解决方案5】:

      您的问题取决于两个条件:

      1. 只有两个线程,一个是生产者,一个是消费者
      2. 结构专为无锁设计

      如果同时满足,你可以放弃锁,或者你需要使用锁来保护队列结构。
      为了释放锁,必须记住更新头部或尾部指针在步骤结束

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-08
        • 2012-06-05
        • 1970-01-01
        相关资源
        最近更新 更多