In this post we will continue to introduce you into OpenMP technology and tell you about some functions and new directives.
OpenMP has some auxiliary functions. Do not forget to enable the header file <omp.h> to be able to use them..
These functions allow you to request for and set various parameters of the OpenMP environment:
If the name of a function begins with omp_set_, it may be called only outside parallel regions. All the rest functions may be used both inside and outside parallel regions.
OpenMP allows you to build parallel code without these functions because there are directives that implement some synchronization types. But in some cases these functions are convenient and even necessary.
OpenMP has two types of locks: simple and nested. The locks of the latter type have the suffix "nest". Locks may be in one of the three states - non-initialized, locked and unlocked.
Simple locks cannot be set more than once even by the same thread. Nested locks are nearly the same as simple ones with the exception that a thread is not locked when trying to set a nested lock already belonging to it.
Here is an example of code where these functions are used. All the threads being created will by turn print the messages "Begin work" and "End work". Between these two messages generated by one thread there may appear messages from the other threads generated when they fail to enter a locked section.
omp_lock_t lock;
int n;
omp_init_lock(&lock);
#pragma omp parallel private (n)
{
n=omp_get_thread_num();
while (!omp_test_lock (&lock))
{
printf("Wait..., thread %d\n", n);
Sleep(3);
}
printf("Begin work, thread %d\n", n);
Sleep(5); // Work...
printf("End work, thread %d\n", n);
omp_unset_lock(&lock);
}
omp_destroy_lock(&lock);
You may expect the following result on a computer with four cores:
Begin work, thread 0
Wait..., thread 1
Wait..., thread 2
Wait..., thread 3
Wait..., thread 2
Wait..., thread 3
Wait..., thread 1
End work, thread 0
Begin work, thread 2
Wait..., thread 3
Wait..., thread 1
Wait..., thread 3
Wait..., thread 1
End work, thread 2
Begin work, thread 3
Wait..., thread 1
Wait..., thread 1
End work, thread 3
Begin work, thread 1
End work, thread 1
Let us finish here with the functions and consider a couple of new directives. These directives may be called options of the parallel regions being created.
Execution of a parallel region by a condition. Several threads are created only if some condition is fulfilled. Otherwise the code continues to execute in serial mode.
For example:
void test(bool x)
{
#pragma omp parallel if (x)
if (omp_in_parallel())
{
#pragma omp single
printf_s("parallelized with %d threads\n",
omp_get_num_threads());
}
else
{
printf_s("single thread\n");
}
}
int _tmain(int argc, _TCHAR* argv[])
{
test(false);
test(true);
return 0;
}
The result:
single thread
parallelized with 4 threads
It serves to explicitly define the number of threads to execute a parallel region. By default, the last value is selected that was returned by the function omp_set_num_threads().
If we modify the example above in the following way:
...
#pragma omp parallel if (x) num_threads(3)
...
the result will be the following:
single thread
parallelized with 3 threads
To be continued in the next issue of "Parallel Notes"...