Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.
Announcements
Welcome to the Intel Community. If you get an answer you like, please mark it as an Accepted Solution to help others. Thank you!
2402 Discussions

how to initialize __thread variable in parallel_do

Xingjing_Lu
Beginner
117 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
Black Belt
117 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

4 Replies
Xingjing_Lu
Beginner
117 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?
RafSchietekat
Black Belt
117 Views
Have a look at task_scheduler_observer for registering the necessary callbacks.

(Optional parallelism without required concurrency is a good thing.)
Alexey_K_Intel3
Employee
117 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).
jimdempseyatthecove
Black Belt
118 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

Reply