pthread mutex 的必要性

Necessity of pthread mutex

我有一个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);
}

这会导致不可预知的行为吗?或者 OS 真的能处理这个问题吗?

在这种情况下是否建议省略互斥量?我注意到如果没有它,这些算法 运行 会快很多。

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

当然,您不需要手动执行此操作。对此有多种实现方式,例如参见 OpenMP 的并行和缩减。

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

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

有多种解决方法是:

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

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

I have an int array[100] and I want 5 threads to calculate the sum of all array elements. Each thread iterates through 20 elements within its dedicated range and writes the sum into a global sum variable.

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

Is a mutex necessary here? There is no synchronization needed since all threads are reading from independent sources.

是 - array 变量的读取是独立的,但是 updating sum 变量不是,所以你需要一个互斥锁来序列化根据您上面的描述,访问 sum

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

Can this lead to unpredictable behavior or does the OS actually handle this?

是的,绝对是。 OS 不会为你处理这个,因为它无法预测 how/when 你将访问内存的不同部分,以及出于什么原因。只要线程中的任何一个可能正在写入数据,就必须在线程之间保护共享数据。所以你几乎肯定会得到错误的结果,因为线程相互更新 sum.

Is it advisable to leave out the mutex in this case? I've noticed that those algorithms run a lot faster without it.

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