Reputation: 2027
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
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