I have this very simple multi-threaded program where I am reading a bunch of numbers and eventually adding them to a global sum
. I am using the local_sum
variable in each thread which I then add to the global sum
. The code is given at the end.
The question is - Do I need to lock this line of code in the thread_runner
function?
sum = local_sum;
I am pretty sure that I do need to lock this however the program always gives the right result anyway. If I do need locks, how do I prove that this implementation is wrong?
Note: I am only interested in mutex locks as the synchronization primitive here. Also please ignore that I have not checked return values.
Code:
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void *thread_runner(void *index);
// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
long array[100000000];
long sum = 0;
int main() {
/* Insert values in the array */
long i = 0;
for (i = 0; i < 100000000; i ) {
array[i] = i 1;
}
/* Declare thread variables */
pthread_t t1, t2, t3, t4;
int index1 = 0;
int index2 = 25000000;
int index3 = 50000000;
int index4 = 75000000;
/* Create 4 threads */
int rc = pthread_create(&t1, NULL, thread_runner, &index1);
rc = pthread_create(&t2, NULL, thread_runner, &index2);
rc = pthread_create(&t3, NULL, thread_runner, &index3);
rc = pthread_create(&t4, NULL, thread_runner, &index4);
/* Wait for threads to complete */
rc = pthread_join(t1, NULL);
rc = pthread_join(t2, NULL);
rc = pthread_join(t3, NULL);
rc = pthread_join(t4, NULL);
printf("Sum: %ld\n", sum);
return 0;
}
void *thread_runner(void *index) {
int i = 0;
int i_index = *((int*)index);
long local_sum = 0;
for (i = i_index; i < i_index 25000000; i ) {
local_sum = array[i];
}
// Do i need to lock the following statement ?
sum = local_sum;
}
CodePudding user response:
how do I prove that this implementation is wrong?
You point to the line sum = local_sum
, and you say, "See! The threads access the same shared variable without any locking and without any other form of synchronization," and then you point to the section in the language spec or you point to some other suitable authority that says "...undefined behavior."
The reason why data races are bad is that they are unpredictable. You cannot depend on a program containing a data race to give the right answer, and you cannot depend on it to give the wrong answer either. You cannot depend on testing to find data races.