【问题标题】:Necessity of pthread mutexpthread互斥锁的必要性
【发布时间】:2015-07-20 23:13:33
【问题描述】:

我有一个int array[100],我想要 5 个线程来计算所有数组元素的总和。

每个线程在其专用范围内迭代 20 个元素并将总和写入全局 sum 变量。

这里需要互斥体吗?不需要同步,因为所有线程都从独立的源读取。

for(i=offset; i<offset+range; i++){
  // not used pthread_mutex_lock(&mutex);
  sum += array[i];
  // not used pthread_mutex_unlock(&mutex);
}

这会导致不可预知的行为,还是操作系统实际上会处理这个问题?

在这种情况下是否建议省略互斥锁?我注意到没有它,这些算法运行得更快。

【问题讨论】:

  • 你所有的线程都在修改同一个变量,所以你当然需要一个互斥体......

标签: c multithreading pthreads mutex


【解决方案1】:

是的,您需要同步,因为所有线程都在同时修改sum。示例如下:

您有 4 个元素 [a1, a2, a3, a4] 和 2 个线程 t1t2sum 的数组。首先让我们假设t1 获取值a1 并将其添加到sum。但这不是原子操作,所以他将sum(它是0)的当前值复制到他的本地空间,我们称之为t1_s,添加到它a1,然后写sum = t1_s。但同时t2做同样的事情,他得到sum的值(为0,因为t1还没有完成它的操作)给t2_s,加上a3并写入sum。所以我们得到了a3suma1 + a3。这称为数据竞争。

对此有多种解决方案:

  1. 您可以像在代码中那样使用mutex,但正如您提到的那样,它可能会很慢,因为互斥锁很昂贵,而且所有其他线程都在等待它。
  2. 创建数组(线程数大小)以计算所有线程的局部总和,然后在一个线程中对该数组进行最后一次归约。无需同步。
  3. 在没有数组的情况下,为每个线程计算本地sum_local,最后使用互斥锁将所有这些和添加到共享变量sum。我想它会更快(但是需要检查)。

但是正如@gavinb 提到的,所有这些仅对大量数据才有意义。

【讨论】:

    【解决方案2】:

    我有一个 int array[100],我想要 5 个线程来计算所有数组元素的总和。每个线程在其专用范围内迭代 20 个元素并将总和写入全局总和变量。

    首先,值得指出的是,这么多线程处理这么少量数据的开销可能不是优势。创建线程、序列化访问并等待它们完成是有成本的。对于这么小的数据集,优化良好的顺序算法可能会更快。用不同数量的线程来衡量加速是一个有趣的练习。

    这里需要互斥体吗?由于所有线程都从独立的源读取,因此不需要同步。

    是的 - array 变量的读取是独立的,但是 更新 sum 变量不是,因此您需要一个互斥锁来序列化对 sum 的访问,根据您的上面的描述。

    然而,这是一种非常低效的计算总和的方法,因为每个线程都将竞争(并等待,因此浪费时间)访问增量 sum。如果您计算每个子集的中间总和(正如@Werkov 也提到的),然后等待它们完成并添加中间总和以创建最终总和,则不会发生读取或写入争用,因此您不需要互斥锁并且每个线程都可以尽可能快地运行。那么,性能的限制因素可能是内存访问模式和缓存行为。

    这会导致不可预知的行为,还是操作系统实际上会处理这个问题?

    是的,当然。操作系统不会为您处理此问题,因为它无法预测您将如何/何时访问内存的不同部分,以及出于什么原因。只要线程中的任何一个可能正在写入数据,就必须在线程之间保护共享数据。所以你几乎肯定会得到错误的结果,因为线程在更新sum 时会相互绊倒。

    在这种情况下是否建议省略互斥锁?我注意到没有它,这些算法运行得更快。

    不,绝对不是。它可能运行得更快,但它几乎肯定不会给你正确的结果!

    【讨论】:

      【解决方案3】:

      在可以以这种方式对数据进行分区的情况下,分区之间不存在依赖关系(即读/写)。在您的示例中,存在 sum 变量的依赖关系,并且互斥锁是必需的。但是,您可以为每个线程设置部分求和累加器,然后只对这些子结果求和,而不需要互斥锁。

      当然,您不必手动执行此操作。这有多种实现方式,例如参见 OpenMP 的并行 for 和 reduction。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-06-05
        • 1970-01-01
        • 2013-06-06
        • 1970-01-01
        • 2017-11-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多