Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pthread mutex not working correctly

I am currently learning C from MIT's Open Courseware course called Practical Programming in C. In discussing race conditions in multithreading, the lecture notes contained an example of a program with a race condition and how it could be resolved using a mutex. The code works as expected on linux systems, but not on OS X.

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

pthread_mutex_t mutex; // Added to fix race condition
unsigned int cnt = 0;

void *count(void *arg) {
    int i;
    for (i = 0; i < 100000000; i++) {
        pthread_mutex_lock(&mutex); // Added to fix race condition
        cnt++;
        pthread_mutex_unlock(&mutex); // Added to fix race condition
    }
    return NULL;
}

int main() {
    pthread_t tids[4];
    int i;
    for (i = 0; i < 4; i++)
        pthread_create(&tids[i], NULL, count, NULL);
    for (i = 0; i < 4; i++)
        pthread_join(tids[i], NULL);
    pthread_mutex_destroy(&mutex); // Added to fix race condition
    printf("cnt = %u\n", cnt);
    return 0;
}

Before adding the mutex and the corresponding function calls, the behavior was as expected, producing a variable fraction of the ideally correct response for cnt (400000000), different on each run. After adding the mutex, this was still happening, although there was an obvious increase in the results, suggesting it had some of the expected effect, but far from perfect.

I tried compiling this program on 3 other computers/VMs: one running OS X 10.10 (the first was running 10.11), one with Kali Linux (essentially Debian Jessie under the hood), and one running Ubuntu. Both of the OS X runs showed the same odd behavior as described. However, both Linux systems produced the perfect 400000000 as expected.

So my question is, why doesn't the mutex work as expected on OS X?

like image 452
saltthehash Avatar asked Dec 15 '22 09:12

saltthehash


2 Answers

You didn't initialize the mutex. You can either do this:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

or in the main function, do this:

if ( pthread_mutex_init( &mutex, NULL) != 0 )
    printf( "mutex init failed\n" );
like image 183
user3386109 Avatar answered Dec 24 '22 19:12

user3386109


The reason why it works with linux is, because under linux :

#define PTHREAD_MUTEX_INITIALIZER { { 0, 0, 0, 0, 0, { 0 } } }

which is exactly how the mutex is initialized anyway, since it is a .bss-variable.

Under MacOSX, it is some other magic value:

#define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}}
#define _PTHREAD_MUTEX_SIG_init     0x32AAABA7

so it indeed has to be initialized to have it working correctly.

like image 44
Ctx Avatar answered Dec 24 '22 20:12

Ctx