Failed Scientist
Failed Scientist

Reputation: 2027

Mutex gone wrong?

I am trying Pthreads and its pretty basic program: I have two shared variables (declared global) among all threads

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

In thread function:

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() in case one needs for reference:

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;

}

OUTPUT

Sum: 40220835000 Sum1: 12502500

Run again

Sum: 38720835000 Sum1: 12502500

Run again

Sum: 39720835000 Sum1: 12502500

PROBLEM

Why I am getting a different value for Sum in each iteration? Rest whole code is working ok and output of Sum1 is correct - no matter how much times do I run the code. (Only issue is in Sum). Am I doing something wrong in use of mutex here?

UPDATE

If I use local variables as @molbdnilo specified in his well detailed answer, this problem is solved. In start, I thought that mutex is irrelevant here but I tested it a number of times and observed the cases when not using a mutex results in recurrence of this problem. So, solution of this problem (courtesy: Answer by @molbdnilo) is to use local variables WITH mutex and I have tested it to work perfectly!

Upvotes: 1

Views: 84

Answers (1)

molbdnilo
molbdnilo

Reputation: 66371

It's not a threading problem – the problem is that even though the order of additions to Sum1 doesn't matter, the order of additions to Sum does.

Consider the much shorter sum 1 + 2 + 3 and the following interleavings

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

You could solve this by having the threads compute their own sum-of-sums independently and adding them afterwards.

(Notice that there's no concurrent mutation here, so locking anything can't make any difference.)

For a more concrete example, let's limit your program to two threads and the sum from 1 to 6.
You then have one thread computing 1 + 2 + 3 and one doing 4 + 5 + 6.

At a glance, thread one should also compute 1 + (1 + 2) + (1 + 2 + 3) and thread 2, 4 + (4 + 5) + (4 + 5 + 6).
Except they don't – every time they use it, Sum may have been modified by the other thread.

So thread one may compute 1 + ((1 + 4) + 2) + ((1 + 4) + 2 + 3), or something else.

When you use local variables, you keep each thread's result independent of the others.

(I think this problem is a pretty good illustration of how shared mutable state can complicate things in unexpected ways, by the way.)

Upvotes: 4

Related Questions