Back to the happy time of single-thread programming, at the end of the function, the only thing you need to worry about is that the local variables on stack will be lost. So advices like "never return pointer to local variables" almost appears on every C/C++ books. However, things get more complicated in multi-threading world. Take OpenMP as an example, the story of parallel construct end is more funny.
1. Let's look at a very simple example:
#pragma omp parallel private(a)
{
TYPE b;
// blah blah blah
}
a and b are both of type TYPE. Suppose TYPE is C++ non-POD type, is there any difference between a and b? The answer is yes. The lifespan of b is the parallel construct, so its destructor should be called in the construct. The lifespan of a is the parallel region, and the destructor of a is part of OpenMP implementation code for the parallel region. The difference of construct and region is subtle, you can refer to OpenMP spec 3.0 (Actually, the construct I mentioned here is not exactly the same in spec). To make it more clearly, see the example below:
#pragma omp parallel for private(a) num_threads(4)
for(i=0;i<10;i++)
{
TYPE b;
}
Through this parallel loop, you will get 4 private copies of a, but 10 copies of b.
Besides destructor of private variables, there are some other things at the end of parallel region.It includes, but not limit to:
1. implicit barrier
2. task scheduling (in implicit barrier)
3. last private copy
4. reduction
The interaction of these operations may trigger some really interesting questions.
2. Let's see a little more complicated example, suppose k is C++ non-POD type.
#pragma omp parallel private(k)
{
#pragma omp task shared(k)
{
... = k;
}
}
OpenMP spec 3.0 does not say a word about the order of task scheduling and destructor of k (Even no "implentation defined"). What it has say is: [14:23-26]:
"A private variable in a task region can be shared by an explicit task region generated during its execution. However, it is the programmer's responsibility to ensure through synchronization that the lifetime of the variable does not end before completion of the explicit task region sharing it." But through these words, user may still confused that whether he need a taskwait to make sure k is still alive during task scheduling.
I'm not trying to give you any assurance here. What I want to say is that you have to undertand very clearly about what you are doing. If you want to return the value to the encounting implicit task, then there must be some instructions that use k after the task. Under this circumstances, please add a taskwait after the explicit task. If you don't want to modify k in the task, then use private/firstprivate instead. Anyway, don't lead yourself into this unspecified hole until specification fullfill it.
3. The lifespan of private variable is not the worst thing of this issue, let's look at this example:
#pragma omp parallel sections lastprivate(k)
{
#pragma omp section
{
// blah blah blah
}
#pragma omp section
{
#pragma omp task shared(k)
{
k = ...
}
}
}
This example shows that the unspecified behavior is not only caused by the lifespan of private variable, but also caused by datarace. Since spec does not talk about the order of implicit barrier and lastprivate copy, the thread of lexically last section may copying its private value, meanwhile some other thread in the team may already reach the implicit barrier and steal the task, then the datarace happens. Again, you should clearly know what exactly you are doing when you write this kind of code.
There are some other similar problems, such as reduction/task, single/task, single/copyprivate, etc. In my opinion, the essence of these problem is that
a) OpenMP gives programmer a slim chance to let one thread access other threads local variable, and only make slimmer behavior specified. See [14: 21-27].
b) There are too many things at the end of parallel region, but we don't know the exactly magic there.
PS: digging the difference between very similar concept and whether the code is specified by the specification is pretty much like the life of a lawyer, and it's really mixed of funny and boring.