Protecting Sharedvariables

3
Protecting Updates of Shared variables: The critical and atomic pragmas are supported by the OpenMP standard for you to protect the updating of shared variables for avoiding data-race conditions. The code block enclosed by a critical section and an atomic pragma are areas of code that may be entered only when no other thread is executing in them. #pragma omp critical { if ( max < new_value ) max = new_value } The named critical sections are used when more than one thread is competing for more than one critical resource. #pragma omp critical(maxvalue) { if ( max < new_value ) max = new_value } It is important to remember that entering nested critical sections runs the risk of deadlock. The following code example code shows a deadlock situation: void dequeue(NODE *node) { #pragma omp critical (x) { node = node->next; } } void do_work(NODE *node) { #pragma omp critical (x) { node->next->data = fn1(node->data); node = dequeue(node) }

Transcript of Protecting Sharedvariables

Page 1: Protecting Sharedvariables

Protecting Updates of Shared variables:

The critical and atomic pragmas are supported by the OpenMP standard for you to protect the updating of shared variables for avoiding data-race conditions. The code block enclosed by a critical section and an atomic pragma are areas of code that may be entered only when no otherthread is executing in them.

#pragma omp critical{if ( max < new_value ) max = new_value}

The named critical sections are used when more than one thread is competing for more than onecritical resource.

#pragma omp critical(maxvalue){if ( max < new_value ) max = new_value}

It is important to remember that entering nested critical sections runs the risk of deadlock. The following code example code shows a deadlock situation:void dequeue(NODE *node){#pragma omp critical (x){node = node->next;}}void do_work(NODE *node){#pragma omp critical (x){node->next->data = fn1(node->data);node = dequeue(node)}}

Thus, the do_work function could never complete. This is a deadlock situation. The simple way to fix the problem in the previous code is to do the inlining of the dequeue function in the do_work function as follows:Deadlock free code:void do_work(NODE *node){#pragma omp critical (x){node->next->data = fn1(node->data);

Page 2: Protecting Sharedvariables

node = node->next;}}

It is sometimes you may require that a statement in a high-level language complete in its entirety before a thread is suspended.For example, a statement x++ is translated into a sequence of machine instructions such as:

load reg, [x];add reg 1;store [x], reg;

It is possible that the thread is swapped out between two of these machine instructions. The atomic pragma directs the compiler to generate code toensure that the specific memory storage is updated atomically. The following code example shows a usage of the atomic pragma.

int main(){ float y[1000];int k, idx[1000];#pragma omp parallel for shared(y, idx)for ( k = 0; k < 8000; k++) {idx[k] = k % 1000;y[idx[k]] = 8.0;}#pragma omp parallel for shared(y, idx)for ( k = 0; k < 8000; k++) {#pragma omp atomicy[idx[k]] += 8.0 * (k % 1000);} return 0;}An expression statement that is allowed to use the atomic pragmamust be with one of the following forms:

x binop = exp x++ ++x x – --x

In the preeding expressions, x is an lvalue expression with scalar type; expr is an expression with scalar type and does not reference the object designed by x; binop is not an overloaded operator and is one of +, *, -, /, &, ^ , | , <<, or >> for the C/C++ language.