Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.
2464 Discussions

how to initialize __thread variable in parallel_do

Xingjing_Lu
Beginner
442 Views
In my app, I used __thread to define the global/static variables. And these varibles need to be initialized one time before thread to execute the task. but the thead in TBB seems can't be contoled by users. where should I insert the initializing code?
0 Kudos
1 Solution
jimdempseyatthecove
Honored Contributor III
442 Views
Lu,

As I understand your postthe issue is:

Although the programmer can make a once onlyglobal initialization of __thread variables, it is not clear as to how to do this initialization per issuance of parallel_do, _for, ...

Here is a suggestion and restriction.

Assume you have a function that is not reentrant (called concurrently by different threads or recursively by same thread).

Assume this function has a parallel_do, which at coding time you have no knowledge as to the number of threads participating in the parallel_do (and which may vary from call to call).

void foo()
{
...
parallel_do(...
{ // body/functor of do
if(firstTime()) init__thread_variables();
...// remainder of body of do
} // end body/functor of do
); // end parallel_do
...
} // void foo()

What I suggest you do is create your __thread context variables for foo and add one extra variable to the context. This variable is a sequence number. Example:

struct fooContext
{
static volatile int sequenceNumber = 0;
int mySequenceNumber;
// your context variables follow
...
fooContext() { mySequenceNumber = -1; }
void next() { ++sequenceNumber; }
void onceOnly()
{
if(mySequenceNumber != sequenceNumber)
{
mySequenceNumber = sequenceNumber;
... your once only initialization code
}
} // void onceOnly
}; // struct fooContext

__thread fooContext myfooContext;
...
void foo()
{
...
myfooContext.next();
parallel_do(...
{ // body/functor of do
myfooContext.onceOnly();
...// remainder of body of do
} // end body/functor of do
); // end parallel_do
...
} // void foo()

Jim Dempsey

View solution in original post

0 Kudos
4 Replies
Xingjing_Lu
Beginner
442 Views
and I think the same quetions are: TBB don't promise the task will be executed in parallel, and it is not clear when the threads are created? how to make the threads to do some initializing work?
0 Kudos
RafSchietekat
Valued Contributor III
442 Views
Have a look at task_scheduler_observer for registering the necessary callbacks.

(Optional parallelism without required concurrency is a good thing.)
0 Kudos
Alexey-Kukanov
Employee
442 Views
You can use tbb::task_scheduler_observer mechanism to initialize some data in each TBB worker thread.

Alternatively, you can use tbb::enumerable_thread_specific for thread-local variables (instead of __thread); in the last case, initialization is done lazily and transparently, you just specify the way it should be done (default constructor, copy of a given value, or a function call).
0 Kudos
jimdempseyatthecove
Honored Contributor III
443 Views
Lu,

As I understand your postthe issue is:

Although the programmer can make a once onlyglobal initialization of __thread variables, it is not clear as to how to do this initialization per issuance of parallel_do, _for, ...

Here is a suggestion and restriction.

Assume you have a function that is not reentrant (called concurrently by different threads or recursively by same thread).

Assume this function has a parallel_do, which at coding time you have no knowledge as to the number of threads participating in the parallel_do (and which may vary from call to call).

void foo()
{
...
parallel_do(...
{ // body/functor of do
if(firstTime()) init__thread_variables();
...// remainder of body of do
} // end body/functor of do
); // end parallel_do
...
} // void foo()

What I suggest you do is create your __thread context variables for foo and add one extra variable to the context. This variable is a sequence number. Example:

struct fooContext
{
static volatile int sequenceNumber = 0;
int mySequenceNumber;
// your context variables follow
...
fooContext() { mySequenceNumber = -1; }
void next() { ++sequenceNumber; }
void onceOnly()
{
if(mySequenceNumber != sequenceNumber)
{
mySequenceNumber = sequenceNumber;
... your once only initialization code
}
} // void onceOnly
}; // struct fooContext

__thread fooContext myfooContext;
...
void foo()
{
...
myfooContext.next();
parallel_do(...
{ // body/functor of do
myfooContext.onceOnly();
...// remainder of body of do
} // end body/functor of do
); // end parallel_do
...
} // void foo()

Jim Dempsey
0 Kudos
Reply