互斥锁出错了?

Mutex gone wrong?

我正在尝试 Pthreads 及其非常基本的程序:我在所有线程中有两个共享变量(声明为全局变量)

long Sum = 0;
long Sum1 = 0;
pthread_mutex_t mutexLock = PTHREAD_MUTEX_INITIALIZER;

在线程函数中:

for(int i=start; i<end; i++) //start and end are being passed to thread and they are being passed correctly
{
 pthread_mutex_lock(&mutexLock);
 Sum1+=i;
 Sum+=Sum1;
 pthread_mutex_unlock(&mutexLock);
}

main() 以备不时之需:

int main()

{

pthread_t threadID[10];

for(int i=0; i<10; i++)
{
 int a = (i*500) + 1;
 int b =(i + 1)*500;

 ThreadStruct* obj = new ThreadStruct(a,b);
 pthread_create(&threadID[i],NULL,ThreadFunc,obj);
}

for(int i=0; i<10; i++)
{
  pthread_join(threadID[i], NULL);
}

cout<<"Sum: "<<Sum<<endl;
cout<<"Sum1: "<<Sum1<<endl;

return 0;

}

输出

总数:40220835000 Sum1: 12502500

运行 再次

总数:38720835000 Sum1: 12502500

运行 再次

总数:39720835000 Sum1: 12502500

问题

为什么我在每次迭代中得到 Sum 的不同值? 其余的整个代码工作正常并且 Sum1 的输出是正确的 - 无论我 运行 代码多少次。 (唯一的问题是总和)。我在这里使用互斥锁是不是做错了什么?

更新

如果我使用局部变量作为 @molbdnilo 在他详细的回答中指定,这个问题就解决了。一开始,我认为互斥锁在这里无关紧要,但我对其进行了多次测试,并观察了不使用互斥锁导致此问题再次出现的情况。所以,这个问题的解决方案(礼貌:@molbdnilo 的回答)是使用带有互斥锁的局部变量,我已经测试它可以完美地工作!

这不是线程问题 – 问题在于,尽管 Sum1 的加法顺序无关紧要,但 Sum 的加法顺序却很重要。

考虑更短的和 1 + 2 + 3 和以下交错

1:

Sum1 = 1 + 2 = 3
Sum = 0 + 3 = 3
Sum1 = 3 + 3 = 6
Sum = 3 + 6 = 9

2:

Sum1 = 1 + 3 = 4
Sum =  0 + 4 = 4
Sum1 = 4 + 2 = 6
Sum = 4 + 6 = 10

3:

Sum1 = 2 + 3 = 5
Sum =  0 + 5 = 5
Sum1 = 5 + 1 = 6
Sum = 5 + 6 = 11

您可以通过让线程独立计算它们自己的总和并在之后添加它们来解决这个问题。

(注意这里没有并发突变,所以锁定任何东西都没有任何区别。)

举一个更具体的例子,让我们将您的程序限制为两个线程,总和从 1 到 6。
然后你有一个线程计算 1 + 2 + 3 和一个做 4 + 5 + 6.

乍一看,线程一也应该计算 1 + (1 + 2) + (1 + 2 + 3) 和线程 2,4 + (4 + 5) + (4 + 5 + 6)
除非他们不这样做——每次他们使用它时,Sum 可能已被其他线程修改。

所以线程一可能会计算 1 + ((1 + 4) + 2) + ((1 + 4) + 2 + 3),或其他东西。

使用局部变量时,每个线程的结果都独立于其他线程。

(我认为这个问题很好地说明了共享可变状态如何以意想不到的方式使事情复杂化。)