martin
martin

Reputation: 3239

Functions in critical sections produce data races in OpenMP

I seem to have a serious lack of understanding of OpenMP concerning the use of critical inside a parallel region. My question is simple: Why does the code below produce warnings with valgrind drd?

#include <stdio.h>
#include <unistd.h>

void A(int* a)
{
   printf("a++\n");
   (*a)++;
}

void B(int* a)
{
   printf("a--\n");
   (*a)--;
}

void f(int* a)
{
#pragma omp critical
   A(a);

   sleep(1); /* work done here */

#pragma omp critical
   B(a);
}

int main(int argc, char** argv)
{
   int i;
   int a = 0;

#pragma omp parallel for
   for(i = 0; i < 4; ++i)
   {
      f(&a);
   }

   return 0;
}

It is compiled it with:

gcc -fopenmp -g -o omptest omptest.c

And the valgrind call is

valgrind --tool=drd  --check-stack-var=yes ./omptest

My understanding was that critical sections should protect me from exactly the warning I get. I spend 2 days now trying to figure out the error but I don't find it. It would be very nice if someone could give me a hint on what exactly I didn't understand.

Any help is appreciated.

EDIT: The (repeating) warning on my 2 CPU machine is:

Thread 2:
Conflicting load by thread 2 at 0x7fefffecc size 4
   at 0x4007DE: A (omptest.c:7)
   by 0x40082E: f (omptest.c:19)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x4E45EE9: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
   by 0x4C2D9E1: ??? (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so)
   by 0x5053E99: start_thread (pthread_create.c:308)
   by 0x535B39C: clone (clone.S:112)
Allocation context: unknown.
Other segment start (thread 1)
   at 0x4C2DF29: pthread_create@* (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so)
   by 0x4E4631B: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
   by 0x400889: main (omptest.c:32)
Other segment end (thread 1)
   at 0x5326F1D: ??? (syscall-template.S:82)
   by 0x5326DBB: sleep (sleep.c:138)
   by 0x40083D: f (omptest.c:21)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x400895: main (omptest.c:32)

Conflicting store by thread 2 at 0x7fefffecc size 4
   at 0x4007E7: A (omptest.c:7)
   by 0x40082E: f (omptest.c:19)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x4E45EE9: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
   by 0x4C2D9E1: ??? (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so)
   by 0x5053E99: start_thread (pthread_create.c:308)
   by 0x535B39C: clone (clone.S:112)
Allocation context: unknown.
Other segment start (thread 1)
   at 0x4C2DF29: pthread_create@* (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so)
   by 0x4E4631B: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
   by 0x400889: main (omptest.c:32)
Other segment end (thread 1)
   at 0x5326F1D: ??? (syscall-template.S:82)
   by 0x5326DBB: sleep (sleep.c:138)
   by 0x40083D: f (omptest.c:21)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x400895: main (omptest.c:32)

Thread 1:
Conflicting load by thread 1 at 0x7fefffecc size 4
   at 0x400805: B (omptest.c:13)
   by 0x40084E: f (omptest.c:24)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x400895: main (omptest.c:32)
Allocation context: unknown.
Other segment start (thread 2)
   at 0x535B361: clone (clone.S:84)
Other segment end (thread 2)
   at 0x5326F1D: ??? (syscall-template.S:82)
   by 0x5326DBB: sleep (sleep.c:138)
   by 0x40083D: f (omptest.c:21)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x4E45EE9: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
   by 0x4C2D9E1: ??? (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so)
   by 0x5053E99: start_thread (pthread_create.c:308)
   by 0x535B39C: clone (clone.S:112)

Conflicting store by thread 1 at 0x7fefffecc size 4
   at 0x40080E: B (omptest.c:13)
   by 0x40084E: f (omptest.c:24)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x400895: main (omptest.c:32)
Allocation context: unknown.
Other segment start (thread 2)
   at 0x535B361: clone (clone.S:84)
Other segment end (thread 2)
   at 0x5326F1D: ??? (syscall-template.S:82)
   by 0x5326DBB: sleep (sleep.c:138)
   by 0x40083D: f (omptest.c:21)
   by 0x400902: main._omp_fn.0 (omptest.c:35)
   by 0x4E45EE9: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
   by 0x4C2D9E1: ??? (in /usr/lib/valgrind/vgpreload_drd-amd64-linux.so)
   by 0x5053E99: start_thread (pthread_create.c:308)
   by 0x535B39C: clone (clone.S:112)

I understand the warning as a data race on a, line 7 and 13 are the (*a)-- and (*a)++ calls.

Upvotes: 2

Views: 987

Answers (1)

Massimiliano
Massimiliano

Reputation: 8032

I was just reading through the documentation of drd, in particular section 8.2.8:

DRD supports OpenMP shared-memory programs generated by GCC. GCC supports OpenMP since version 4.2.0. GCC's runtime support for OpenMP programs is provided by a library called libgomp. The synchronization primitives implemented in this library use Linux' futex system call directly, unless the library has been configured with the --disable-linux-futex option. DRD only supports libgomp libraries that have been configured with this option and in which symbol information is present. For most Linux distributions this means that you will have to recompile GCC. See also the script drd/scripts/download-and-build-gcc in the Valgrind source tree for an example of how to compile GCC. You will also have to make sure that the newly compiled libgomp.so library is loaded when OpenMP programs are started.

If you didn't recompile libgomp this could be a possible explanation of the odd behavior you are encountering.

Upvotes: 1

Related Questions