Synchronization

OpenMP will not check the data dependencies, data conflicts, race conditions, deadlocks, or code sequences for you. You have to deal with those problems by yourself. OpenMP can have some ways to solve it, but you can also give a better solution(e.g. partition the data properly).

Here we have a race condition problem in the OpenMP version:

race.c
#include <stdio.h>
#include <omp.h>

int main() {
    omp_set_num_threads(2);
    int a=0;
    int i;
    #pragma omp parallel for
    for(i=0; i<20000000; i++) {
        a++;
    }
    printf("a = %d\n", a);
    return 0;
}

Compile it and run it multiple times, you will found that your results will vary each time you run it. This is the effect of race condition.

$ gcc -o race race.c -fopenmp
$ ./race
a = 10406097
$ ./race
a = 15896259
$ ./race
a = 10927636
$ ./race
a = 11958374
$ ./race
a = 15680889

How to solve it in OpenMP using the build-in solutions?

  • critical: Mutual exclusion, Only one thread at a time can enter a critical region.

critical.c
#include <stdio.h>
#include <omp.h>

int main() {
    omp_set_num_threads(2);
    int a=0;
    int i;
    #pragma omp parallel for
    for(i=0; i<20000000; i++) {
        #pragma omp critical
        {
            a++;
        }
    }
    printf("a = %d\n", a);
    return 0;
}

After compiling and running multiple times, you will fount you can only get one answer "20000000", which is just what we want. (You will also find that the running time increases compared with the former one, it's normal.)

$ ./critical
a = 20000000
  • reduction(op:list): A local copy of each list variable is made and initialized depending on the "op". It will do calculation related with "op" after all the thread finish.

reduction.c
#include <stdio.h>
#include <omp.h>

int main() {
    omp_set_num_threads(2);
    int a=0;
    int i;
    #pragma omp parallel for reduction(+:a)
    for(i=0; i<20000000; i++) {
        a++;
    }
    printf("a = %d\n", a);
    return 0;
}

Try it by yourself! (You can also pay attention to the running time) Notice that the C compilers for OpenMP also support*, -, &, |, ^, &&, ||in reduction.

  • lock routines: just like lock like what you did in pThread.

lock.c
#include <stdio.h>
#include <omp.h>

int main() {
    omp_set_num_threads(2);
    int a=0;
    int i;
    omp_lock_t lock;
    omp_init_lock(&lock);
    #pragma omp parallel for
    for(i=0; i<20000000; i++) {
        omp_set_lock(&lock);
        a++;
        omp_unset_lock(&lock);
    }
    printf("a = %d\n", a);
    return 0;
}

Try it by yourself and compare the time using different methods!

OpenMP also has many other solutions to synchronization problems, such as barrier, master, single, ordered. You can Google them and get more information about them.

These examples are all usingfor, can you solve synchronization problems not usingfor?

Last updated