Multithreading in C – C. Mutex

Multithreading in C – C. Mutex … here is a solution to the problem.

Multithreading in C – C. Mutex

My code does the following: create N threads, each incrementing the global variable counter M times. I’m using a mutex to make sure the final value of the counter is M*N.

I would like to observe the absence of mutexes to get different counter values in order to properly evaluate the work of mutexes. I commented out the mutexe, but the result is the same. Should I let them sleep randomly for a while? How should I proceed?

#include <stdio.h>
#include <pthread.h>

#define N 10
#define M 4

pthread_mutex_t mutex;
int counter=0;

void *thread_routine(void *parameter)
{
    pthread_mutex_lock(&mutex);
    int i;
    for (i=0; i<M; i++)
        counter++;
    pthread_mutex_unlock(&mutex);
}

int main(void)
{
    pthread_t v[N];
    int i;

pthread_mutex_init(&mutex,NULL);

for (i=0; i<N; i++)
    {
        pthread_create(&v[i],NULL,thread_routine,NULL);
    }

for (i=0; i<N; i++)
    {
        pthread_join(v[i],NULL);
    }

printf("%d %d\n",counter,N*M);
    if (N*M==counter)
        printf("Success!\n");
    pthread_mutex_destroy(&mutex);

return 0;
}

Solution

I don’t know what compiler you’re using, but in this case, g++ completely eliminates the thread and calculates the final value of the counter at compile time.
To prevent this optimization, you can make counter variables variable

volatile int counter=0;

Because this will tell the compiler that the variable can be changed at any time through external resources, it is forced not to make any optimizations to the variable that may have side effects. Because external resources may change the value, the final value may not be the result of N*M, so the value of the counter is calculated at run time.
Also, what WhozCraig said in his comment is likely to apply to your situation. But I think he was referring to M, not N.

Except for your original problem: when you read counters after all threads have joined, it might be worth giving each thread its own counter and summing the counters for all threads when all threads have finished their calculations. This allows you to calculate the final value without any locking or atomic manipulation.

Edit:

Your first mutex test looks like this

#define N 10
#define M 10000000

pthread_mutex_t mutex;
volatile int counter=0;

void *thread_routine(void *parameter)
{
    pthread_mutex_lock(&mutex);
    int i;
    for (i=0; i<M; i++)
        counter++;
    pthread_mutex_unlock(&mutex);
}

Your second does not have a test for mutexes like this

#define N 10
#define M 10000000

pthread_mutex_t mutex;
volatile int counter=0;

void *thread_routine(void *parameter)
{
  pthread_mutex_lock(&mutex);
    int i;
    for (i=0; i<M; i++)
        counter++;
  pthread_mutex_unlock(&mutex);
}

The second test will have the expected race condition when incrementing the counter variable.

You can compile using gcc -O3 -lpthread test.c

Related Problems and Solutions