Search code examples
multithreadingpthreadsparallel-processingmulticoreatomic

How to verify atomic operations on multithreaded and multicore platforms in C?


I am trying to understand the atomic operations, and I have prepared the sample code below. But I am getting the same result - 150 - when I define one of these conditional compilation flags - MUTEX, ATOMIC and NONE.

How can I verify inter-threaded arithmetic operations are working properly?

My pc is "2.6.35-30-generic #61-Ubuntu SMP x86_64 GNU/Linux" and it has 4 cores.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/types.h>

#define THREAD_NUM 10
#define INC_NUM 15

//#define MUTEX
#define ATOMIC
//#define NONE

volatile int g_counter = 0;


void *thread_func(void *ptr);
pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;

int main(int argc ,char **argv) {

    pthread_t thread[THREAD_NUM];

    int  iret[THREAD_NUM];
    int nt;
    for (nt = 0; nt<THREAD_NUM; nt++)
        iret[nt] = pthread_create( &thread[nt], NULL, thread_func, NULL);

    for (nt = 0; nt<THREAD_NUM; nt++)
        pthread_join(thread[nt], NULL);

    printf("counter val = %d\n", g_counter);
    return 0;
}


void *thread_func(void *ptr) {
    int cnt;
    for (cnt = 0; cnt<INC_NUM; cnt++) {
#ifdef MUTEX
        pthread_mutex_lock( &thread_mutex );
        g_counter++;
        pthread_mutex_unlock(&thread_mutex);
#endif
#ifdef ATOMIC
        __sync_fetch_and_add(&g_counter, 1);
#endif
#ifdef NONE
        g_counter++;
#endif
    }

    return NULL;
}

Solution

  • When I ran your code with INC_NUM of 100000, I got significantly differing values -- with NONE defined, the sum was never the correct value of 1000000. Your INC_NUM value is too small.

    There was no difference between MUTEX and ATOMIC, (nor should there be, of course), although I assume there will be performance differences.

    You might find it informative to modify your code to show the order in which threads start and finish, as below:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <pthread.h>
    #include <sys/types.h>
    
    #define THREAD_NUM 10
    #define INC_NUM 100000
    
    //#define MUTEX
    //  #define ATOMIC
    #define NONE
    
    volatile int g_counter = 0;
    
    
    void *thread_func(void *ptr);
    pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
    
    int main(int argc ,char **argv) {
    
        pthread_t thread[THREAD_NUM];
    
        int  iret[THREAD_NUM];
        int nt;
        for (nt = 0; nt<THREAD_NUM; nt++)
            iret[nt] = pthread_create( &thread[nt], NULL, thread_func, (void *)nt);
    
        for (nt = 0; nt<THREAD_NUM; nt++)
            pthread_join(thread[nt], NULL);
    
        printf("counter val = %d\n", g_counter);
        return 0;
    }
    
    
    void *thread_func(void *ptr) {
        int cnt;
        printf("Thread %d started.\n", (int)ptr);
        for (cnt = 0; cnt<INC_NUM; cnt++) {
    #ifdef MUTEX
            pthread_mutex_lock( &thread_mutex );
            g_counter++;
            pthread_mutex_unlock(&thread_mutex);
    #endif
    #ifdef ATOMIC
            __sync_fetch_and_add(&g_counter, 1);
    #endif
    #ifdef NONE
            g_counter++;
    #endif
        }
        printf("Thread %d finished.\n", (int)ptr);
    
        return NULL;
    }