1

i have a very weird question about OpenMP. for the example below, the variable "a" should be "shared" by default according to the rule of OpenMP (Chapter:2.9.1.2: Data-sharing Attribute Rules for Variables Referenced in a Region but not in a Construct: Objects with dynamic storage duration are shared). when i run it , i get:

adre1: 0x7f51640008c0
adre2: 0x7f51640008c0
adre3: 0x1122d40
adre4: 0x7f51640008c0

which makes sense.

void jl()
{

   char *a=(char *)malloc(10);
   printf("adre1: %p\n",a);
   #pragma omp task
   {

       printf("adre2: %p\n",a); 
       a=(char *)malloc(10);
       printf("adre3: %p\n",a);
   }
   #pragma omp taskwait
   printf("adre4: %p\n",a);
}

But if i add "shared" after task like this :

void jl()
{
    char *a=(char *)malloc(10);
    a[1]='c';
    printf("adre1: %p\n",a);

    #pragma omp task shared(a)
    {

        printf("adre2: %p\n",a);
        a=(char *)malloc(10);
        printf("adre3: %p\n",a);
    }
    #pragma omp taskwait
    printf("adre4: %p\n",a);
}

the output is :

adre1: 0x1cefd40
adre2: 0x1cefd40
adre3: 0x7f93d00008c0
adre4: 0x7f93d00008c0

i was confused here. see when you redirect the address of variable "a" inside the task, it is visible outside, but i can not find such a data-attribute rule in Openmp. and what is the difference between these two cases?

user3220866
  • 31
  • 1
  • 3

2 Answers2

1

The a variable in the first case is firstprivate. This is the default implicitly determined data-sharing attribute for variables that are referenced in task constructs if no other rule apply. Indeed, if you take the rules (found in §2.9.1.1) and go over them one by one, you would see that none of the other ones apply:

  • In a parallel or task construct, the data-sharing attributes of these variables are determined by the default clause, if present.

Not the case since there is no default clause in your task construct.

  • In a parallel construct, if no default clause is present, these variables are shared.

Not a parallel construct.

  • For constructs other than task, if no default clause is present, these variables inherit their data-sharing attributes from the enclosing context.

Again, that is a task construct and the rule does not apply.

  • In a task construct, if no default clause is present, a variable that in the enclosing context is determined to be shared by all implicit tasks bound to the current team is shared.

a is a variable with an automatic storage duration, declared in a called routine. As such its data-sharing attribute is predetermined as private (see §2.9.1.2) and the rule does not apply.

  • In a task construct, if no default clause is present, a variable whose data-sharing attribute is not determined by the rules above is firstprivate.

That catch-all rule is the only one that applies.

Firstprivate variables take initially the value of the outside variable but any changes to them are not visible outside the construct/region. This is consistent with OpenMP tasks functioning like closures - tasks capture the value of their variables at the moment when created and use those values later one when the task is executed.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186
  • as you said:" "a is a variable with an automatic storage duration, declared in a called routine. As such its data-sharing attribute is predetermined as private (see §2.9.1.2) and the rule does not apply. But i think "a" is a variable with a dynamic storage duration. it should be shared. see "a" is allocated using "malloc". – user3220866 Mar 07 '14 at 17:20
  • again, if i am wrong, can you give me an example, when this rule applies: Objects with dynamic storage duration are shared. Thank you! – user3220866 Mar 07 '14 at 17:24
  • The dynamically allocated memory is shared in the sense that it could be accessed from any thread. But this can only be done through a pointer and the pointer itself, i.e. the place in memory where the target address is stored, is firstprivate. It means that when the task is queued a new private pointer is created and its value is initialised to the value of the original `a`. While the pointer is different, it points to the same memory region as `a` and the information pointed is that way shared. The compiler won't allocate a new memory region automatically. – Hristo Iliev Mar 07 '14 at 17:46
  • The confusion most likely comes from the fact that the object with dynamic storage duration is _not_ the same thing as the pointer used to access it. – Hristo Iliev Mar 07 '14 at 17:52
  • so "Objects with dynamic storage duration are shared" means that only the content in the targeted address is shared but not the pointer variable itself? when we add shared(a), it means that the variable "a" itself is shared. Am i right? – user3220866 Mar 07 '14 at 18:00
  • Correct! `shared(a)` makes the pointer shared, e.g. assignments to `a` (but not to `*a` or to `a[i]`) change the pointer value (and not the value it points to) in all threads. – Hristo Iliev Mar 07 '14 at 18:10
  • @user3220866, see my answer here http://stackoverflow.com/questions/22204495/local-pointers-in-openmp/22221504#22221504. I print out both the address of the pointer and the value of the pointer (the memory address it points to for firstprivate for static and dynamic arrays. You can see that for dynamic memory with firsprivate the address of each pointer is different but the value they store are the same. – Z boson Mar 07 '14 at 19:34
-1

The answer is compiler dependent, on some implementations the default sharing = firstprivate while on others (incl. mine) the default=shared,

for example : void main() {

    char *a=(char *)malloc(10);
       printf("adre1: %p\n",a);

    omp_set_num_threads(1);
    #pragma omp parallel 
    {

    //#pragma omp single
    {
       #pragma omp task firstprivate(a)
       {

           printf("adre2: %p\n",a);
           a=(char *)malloc(10);
           printf("adre3: %p\n",a);
       }
       #pragma omp taskwait

       printf("adre4: %p\n",a);
    }

       printf("adre5: %p\n",a);
    }

       printf("adre6: %p\n",a);
    }

output :

  • adre1: 0x948a008
  • adre2: 0x948a008 <
  • adre3: 0x948a6b0 <<
  • adre4: 0x948a008 <
  • adre5: 0x948a008
  • adre6: 0x948a008

and if we change #pragma omp task firstprivate(a) ==> #pragma omp task shared(a)

  • adre1: 0x9b96008
  • adre2: 0x9b96008 <
  • adre3: 0x9b966b0 <<
  • adre4: 0x9b966b0 <
  • adre5: 0x9b966b0
  • adre6: 0x9b966b0

in future to avoid confusions related to data sharing ,always use :

#pragma omp parallel default(none) 
{
//my code
}.
puneet336
  • 433
  • 5
  • 20
  • That's not correct. The default in a parallel construct is determined by the default clause which if not defined defaults to shared (see Hristo's answer). And I don't think it's good advice to use default(none). It just causes confusing having to define everything shared and private. In practice I almost never have to explicitly define anything public or private (except for some C89 examples on SO). – Z boson Mar 07 '14 at 14:13
  • here i think we are talking about different story. see my example is that the task directive is an orphaned directive, but yours is not. – user3220866 Mar 07 '14 at 17:26
  • You show a case where the `task` construct is lexically nested inside a `parallel` region. `a` is declared outside the scope of the parallel region and as such is predetermined to be shared inside the region and that is further carried into the task unless `a` is explicitly made firstprivate. Yours is a completely different case as noted by the OP and not a compiler-dependent behaviour. – Hristo Iliev Mar 07 '14 at 18:04