互斥粒度

时间:2014-09-25 07:22:21

标签: c++ multithreading

我对线程有疑问。众所周知,当我们调用互斥锁(lock)时,这意味着线程继续执行其他线程不中断的代码部分,直到遇到互斥锁(解锁)。 (至少这是他们在书中所说的)所以我的问题是,实际上是否有可能有几个不会相互干扰的作用域WriteLocks。例如:

如果我有一个没有任何新元素的N元素的缓冲区,但是有了高频率更新(比如Kth元素的更改值),可以在每个元素上设置不同的锁定,以便唯一的时间线程停止等待是否实际上有2个或更多线程正在尝试更新同一个元素?

5 个答案:

答案 0 :(得分:7)

回答关于N个互斥体的问题:是的,这确实是可能的。互斥锁保护哪些资源完全取决于您作为该互斥锁的用户。

这会导致问题的第一个(陈述)部分。互斥锁本身并不能保证线程不会中断。所有它保证是MUTual EXclusion - 如果线程B试图锁定线程A已锁定的互斥锁,则线程B将阻塞(不执行代码),直到线程A解锁互斥锁。

这意味着可以使用互斥锁 来保证线程不间断地执行代码块;但只有当所有线程遵循该代码块周围的相同互斥锁定协议时,此方法才有效。这意味着您有责任为每个互斥锁分配语义(或含义),并正确遵守代码中的语义。

如果您决定语义为“我有N个数据元素的数组a和N个互斥体的数组m,那么访问a[i]只能在{ {1}}被锁定,“那就是它的工作原理。

需要始终坚持使用相同的协议,这就是为什么你应该通过某种方式将互斥体及其保护的代码/数据封装在类中,这样外部代码就不需要知道协议。它只知道“调用这个成员函数,同步将自动发生。”这种“自动化”将是正确实施该协议的类。

答案 1 :(得分:4)

在每个元素的互斥锁和每个元素的互斥锁之间进行判断时,一个重要的考虑因素是是否存在操作 - 例如跟踪“使用中”数组元素的数量,“活动”元素或移动指针到 - 数组到一个更大的缓冲区 - 只能由一个线程安全地完成,而所有其他线程都被阻塞。

较少但有时重要的考虑因素是更多互斥量使用的额外内存量。

如果您真的需要在竞争激烈的多线程程序中尽快进行此类更新,您可能还需要了解无锁原子类型及其比较和交换/交换操作,但我建议不要考虑除非对整个程序性能进行分析,否则对整个程序性能的影响非常重要。

答案 2 :(得分:1)

互斥锁不会阻止其他线程完全运行,它只会阻止其他线程锁定相同的互斥锁。即当一个线程保持互斥锁被锁定时,操作系统继续执行上下文切换,让其他线程也运行,但如果任何其他线程试图锁定相同的互斥锁,则执行将暂停,直到互斥锁被解锁。

所以是的,你确实可以拥有几个不同的互斥锁并独立锁定/解锁它们。只要注意死锁,即如果一个线程一次可以锁定多个互斥锁,则可能遇到线程1已锁定互斥锁A并尝试锁定互斥锁B但阻塞的情况,因为线程2已锁定互斥锁B正试图锁定互斥锁A ..

答案 3 :(得分:0)

您的用例不完全清楚:

  1. 线程获得分配的缓冲区,它们必须工作
  2. 线程有一些结果并请求一个特殊的缓冲区来更新。
  3. 在第一个变体上,您需要一些为线程分配缓冲区的赋值逻辑。 这种逻辑必须以原子方式进行。所以最好是使用互斥锁来保护赋值逻辑。

    在另一个变体上,最好有一个互斥体矢量,每个缓冲元素一个。

    在这两种情况下,缓冲区都不需要保护,因为它(或者更好的每个字段)一次只能从一个线程访问。

    您也可以告知自己有关信号量的信息。它们包含一个计数器,允许管理数量有限但不止一个的资源。互斥量是信号量的特例,n = 1。

答案 4 :(得分:0)

每个条目都可以使用互斥锁,C ++ 11互斥锁可以很容易地转换为自适应自旋锁,因此可以实现良好的CPU /延迟权衡。

或者,如果你需要非常低的延迟但有足够的CPU,你可以使用原子"忙"每个条目标记并在争用的紧密比较交换循环中旋转。

但是,根据经验,当通过命令队列(或者在目的地连接较小的不可变缓冲区的队列)和单个线程处理来序列化并发写入时,可以实现最佳性能和可伸缩性队列。