Simple Tutorial with OpenMP: How to Use Parallel Block in C/C++ using OpenMP?


OpenMP (www.openmp.org) makes writing the Multithreading code in C/C++ so easy. OpenMP is cross-platform can normally ben seen as an extenstion to the C/C++, Fortran Compiler i.e. OpenMP hooks the compiler so that you can use the specification for a set of compiler directives, library routines, and environment variables in order to specify shared memory parallelism.

OpenMP Hello World Example

Let’s name the following first OpenMP example hello_openmp.c

1
2
3
4
5
6
7
8
9
#include <stdio.h>
 
int main() {
  #pragma omp parallel
  {
    printf("https://helloacm.com\n");     
  }
  return 0;
}
#include <stdio.h>

int main() {
  #pragma omp parallel
  {
    printf("https://helloacm.com\n");     
  }
  return 0;
}

Let’s compile the code using the gcc/g++ compiler.

1
gcc -o hello_openmp hello_openmp.c -fopenmp
gcc -o hello_openmp hello_openmp.c -fopenmp

Run the generated exectuable hello_openmp

1
2
3
4
lychee@uploadbeta:~$ ./hello_openmp
https://helloacm.com
https://helloacm.com
https://helloacm.com
lychee@uploadbeta:~$ ./hello_openmp
https://helloacm.com
https://helloacm.com
https://helloacm.com
openmp_multiple_threads_master Simple Tutorial with OpenMP: How to Use Parallel Block in C/C++ using OpenMP? c / c++ multithreading OpenMP tutorial

openmp_multiple_threads_master

The OpenMP code Parallel Construct basically says: “Hey, I want the following statement/block to be executed by multiple threads at the same time.”, So depending on the current CPU specifications (number of cores) and a few other things (process usage), a few threads will be generated to run the statement block in parallel, after the block, all threads are joined.

You may also see the messages printing interleaving each other depending on the OS CPU task scheduling. e.g. if you have lots of print-outs.

Explicitly Specify the Number of Threads in OpenMP

If you want to specify explicitly the number the threads to execute the parallel statement block, use the num_threads() compiler directive, as shown below.

1
2
3
4
5
6
7
8
#include <stdio.h>
int main() {
  #pragma omp parallel num_threads(3)
  {
    printf("https://helloacm.com\n");
  }
  return 0;
}
#include <stdio.h>
int main() {
  #pragma omp parallel num_threads(3)
  {
    printf("https://helloacm.com\n");
  }
  return 0;
}

This will guarantee only three threads are generated. Please note that it doesn’t have to be constant, actually, you can pass almost any expressions, including variables.

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main() {
  int x = 1;
  int y = x + 2;
  #pragma omp parallel num_threads(y * 3)
  {
    printf("https://helloacm.com\n");
  }
  return 0;
}
#include <stdio.h>
int main() {
  int x = 1;
  int y = x + 2;
  #pragma omp parallel num_threads(y * 3)
  {
    printf("https://helloacm.com\n");
  }
  return 0;
}

In this example, 9 threads will be running at the same time (x=1, y=3, y*3=9), and you should see 9 lines of messages.

Get Number of Threads and Current Thread ID

How to distinguish the threads? OpenMP provides the omp_get_thread_num() function in the header file omp.h. To get the number of total running threads in the parallel block, you can use function omp_get_num_threads.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <omp.h>
 
int main() {
  #pragma omp parallel num_threads(3)
  {
    int id = omp_get_thread_num();
    int data = id;
    int total = omp_get_num_threads();
    printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
  }
  printf("parallel for ends.\n");
  return 0;
}
#include <stdio.h>
#include <omp.h>

int main() {
  #pragma omp parallel num_threads(3)
  {
    int id = omp_get_thread_num();
    int data = id;
    int total = omp_get_num_threads();
    printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
  }
  printf("parallel for ends.\n");
  return 0;
}

Compile and Run, we have something like this:

1
2
3
4
Greetings from process 0 out of 3 with Data 0
Greetings from process 2 out of 3 with Data 2
Greetings from process 1 out of 3 with Data 1
parallel for ends.
Greetings from process 0 out of 3 with Data 0
Greetings from process 2 out of 3 with Data 2
Greetings from process 1 out of 3 with Data 1
parallel for ends.

Please note that the variables defined inside the block are separate copies between threads, so it is gaureented that data field sent to console is unique. If you move the data outside the parallel struct, like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <omp.h>
 
int main() {
  int data;
  #pragma omp parallel num_threads(3)
  {
    int id = omp_get_thread_num();
    data = id; // threads may interleaving the modification
    int total = omp_get_num_threads();
    printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
  }
  printf("parallel for ends.\n");
  return 0;
}
#include <stdio.h>
#include <omp.h>

int main() {
  int data;
  #pragma omp parallel num_threads(3)
  {
    int id = omp_get_thread_num();
    data = id; // threads may interleaving the modification
    int total = omp_get_num_threads();
    printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
  }
  printf("parallel for ends.\n");
  return 0;
}

You may have some output like this (data may not be unique anymore):

1
2
3
4
Greetings from process 2 out of 3 with Data 2
Greetings from process 0 out of 3 with Data 2
Greetings from process 1 out of 3 with Data 1
parallel for ends.
Greetings from process 2 out of 3 with Data 2
Greetings from process 0 out of 3 with Data 2
Greetings from process 1 out of 3 with Data 1
parallel for ends.

You can also tells the compiler which variables should be private so each thread has its own copy by using directive private field.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <omp.h>
int main() {
  int data, id, total;
  // each thread has its own copy of data, id and total.
  #pragma omp parallel private(data, id, total) num_threads(6) 
  {
    id = omp_get_thread_num();
    total = omp_get_num_threads();
    data = id;      
    printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
  }
  printf("parallel for ends.\n");
  return 0;
}
#include <stdio.h>
#include <omp.h>
int main() {
  int data, id, total;
  // each thread has its own copy of data, id and total.
  #pragma omp parallel private(data, id, total) num_threads(6) 
  {
    id = omp_get_thread_num();
    total = omp_get_num_threads();
    data = id;      
    printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
  }
  printf("parallel for ends.\n");
  return 0;
}

private(data, id, total) asks OpenMP to create individual copies of these variables for each thread.

1
2
3
4
5
6
7
Greetings from process 5 out of 6 with Data 5
Greetings from process 4 out of 6 with Data 4
Greetings from process 2 out of 6 with Data 2
Greetings from process 3 out of 6 with Data 3
Greetings from process 1 out of 6 with Data 1
Greetings from process 0 out of 6 with Data 0
parallel for ends.
Greetings from process 5 out of 6 with Data 5
Greetings from process 4 out of 6 with Data 4
Greetings from process 2 out of 6 with Data 2
Greetings from process 3 out of 6 with Data 3
Greetings from process 1 out of 6 with Data 1
Greetings from process 0 out of 6 with Data 0
parallel for ends.

Critical Sections

You can also fix the above example by using locks, mutexs, critical sections etc. But the easiest method will be to use the omp critical directive as provided by OpenMP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <omp.h>
 
int main() {
  int data;
  #pragma omp parallel num_threads(3)
  {
    int id = omp_get_thread_num();    
    int total = omp_get_num_threads();
    #pragma omp critical 
    { // make sure only 1 thread exectutes the critical section at a time.
        data = id; // threads may interleaving the modification
        printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
    }
  }
  printf("parallel for ends.\n");
  return 0;
}
#include <stdio.h>
#include <omp.h>

int main() {
  int data;
  #pragma omp parallel num_threads(3)
  {
    int id = omp_get_thread_num();    
    int total = omp_get_num_threads();
    #pragma omp critical 
    { // make sure only 1 thread exectutes the critical section at a time.
        data = id; // threads may interleaving the modification
        printf("Greetings from process %d out of %d with Data %d\n", id, total, data);
    }
  }
  printf("parallel for ends.\n");
  return 0;
}

The omp ciritical ensures only 1 thread enters the block at a time.

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
1131 words
Last Post: Model-View-Controller Explained in C++
Next Post: How to Download Instagram Videos using PHP and Javascript?

The Permanent URL is: Simple Tutorial with OpenMP: How to Use Parallel Block in C/C++ using OpenMP?

Leave a Reply