Tanatos Daniel
Tanatos Daniel

Reputation: 578

Multithreading in c. Mutexes

My code does the following: creates N threads, each one of them increments the global variable counter M times. I am using a mutex in order to assure the final value of counter is M*N.

I would like to observe the situation without a mutex, to obtain a different value for counter, in order to proper assess the mutex's work. I commented out the mutex, but the results are the same. Should I put them to sleep for a random period of time? How should I procede?

#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;
}

Upvotes: 3

Views: 176

Answers (1)

foobar
foobar

Reputation: 606

I don't know what compiler you used, but g++ in this case would completely eliminate the threads and calculate the final value of counter at compile time. To prevent that optimization you can make the counter variable volatile

volatile int counter=0;

As this will tell the compiler that the variable can change at any time by external resources, it is forced to not to do any optimizations on that variable that could have side effects. As an external resource could change the value, the final value might not be the result of N*M and therefore the value of counter will be calculated at run-time. Also what WhozCraig stated in his comment will most likely apply in your case. But I think he meant M, not N.

Additionally to your original question: As you read the counter once all threads are joined, it might be worth to give each thread its own counter and sum all threads' counters when they finished computation. This way you can compute the final value without any locks or atomic operations.

Edit:

Your first test with mutex would look 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);
}

and your second test without mutex 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);
}

while the second test will have the expected race conditions when incrementing the counter variable.

Compilation can be done using gcc -O3 -lpthread test.c

Upvotes: 4

Related Questions