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

VC++ Release Optimizations Breaking Code

oneminute
Beginner
952 Views
I'm having a strange problem that only occurs in release mode, when compiler optimizations are turned on. I set a variable in my task to be returned and read by the main thread to close the application. In debug mode or release mode without compiler optimizations this runs the way I expect it to. In release mode with optimizations on, the variable changed in the task doesn't change the variable in the main loop.

Here is what the main loop looks like. It should exit the program when the thread returns while still being able run some concurrent code in the main thread. In release mode however, the program gets stuck in the while loop even after the thread has returned and changed *isAlive.

[cpp]{
bool isAlive = true;

MyTask& myTask = *new(task::allocate_root()) MyTask(n, &isAlive);
task::spawn(myTask);

while(isAlive)
{ } // main thread loop

return 0;
}[/cpp]

And here is what the task looks like:

[cpp]class MyTask : public task
{
public:
int n;
bool* isAlive;

MyTask(int n_, bool* isAlive_) : n(n_), isAlive(isAlive_)
{ }

task* execute()
{
// ...
// omitted

if(n < MAX)
{
*isAlive = false;
return NULL;
}
}
};[/cpp]

I feel like I'm doing it exactly how it's done in the fibonacci tutorial for the task scheduler, so I can't understand what the problem could be.

Any help is greatly appreciated.
0 Kudos
1 Solution
RafSchietekat
Valued Contributor III
952 Views

If you want to tell the event handler thread to quit, post a quit message. The event handler can theninform other threads to end by, e.g.,setting an atomic flag that they should consult from time to time telling them to wind down execution and exit, and when all those threads have been joined the program can exit cleanly.For some programs it may be safe to just exit fromthemain threadwithout waiting.

If anyone favours a different design, I'm interested to hear about it.

View solution in original post

0 Kudos
11 Replies
RafSchietekat
Valued Contributor III
952 Views
isAlive should probably be atomic instead if you really want to do this, but it seemsbetter to wait for the task or use a condition variable than to just busy-wait for an unbounded amount of time.
0 Kudos
oneminute
Beginner
952 Views
I simplified the code to make the problem more legible, but what the task is actually doing is running a message handler until destroy is called on the application from within the task. So I need it to run throughout the existance of the program until a user exits the program, and then bubble up the message to the main thread so it can close everything down. I am very new to parallel theory and implementation, so if this is a naive approach I would love some insight :)
0 Kudos
RafSchietekat
Valued Contributor III
952 Views
Don't make a task run a message handler: that's a thread's job.
0 Kudos
oneminute
Beginner
952 Views
Just to make sure I have the logic right - anything that needs its own dedicated thread indefinitely shouldn't be handled by TBB, and should just be put on its own thread with something like CreateThread?

Or is there a different reason a message handler should be in a thread instead of a task?

(Thanks for the help btw)
0 Kudos
RafSchietekat
Valued Contributor III
952 Views
A task is meant to do a finite amount of work. Otherwise, use a thread by whatever interface you prefer: std::thread, tbb::tbb_thread, ...
0 Kudos
oneminute
Beginner
952 Views
What is the best way to flag the program to exit from within the thread?
0 Kudos
RafSchietekat
Valued Contributor III
953 Views

If you want to tell the event handler thread to quit, post a quit message. The event handler can theninform other threads to end by, e.g.,setting an atomic flag that they should consult from time to time telling them to wind down execution and exit, and when all those threads have been joined the program can exit cleanly.For some programs it may be safe to just exit fromthemain threadwithout waiting.

If anyone favours a different design, I'm interested to hear about it.

0 Kudos
oneminute
Beginner
952 Views
Would this work for both threads and tasks when they are used in the same application?
0 Kudos
RafSchietekat
Valued Contributor III
952 Views
Sure, but if you instead use TBB's task cancellation mechanism a potentially considerable number of taskswould not get created and spawned unnecessarily in the first place, while for any potentially long-running tasks already executing you could have them poll the cancellation status and act accordingly.
0 Kudos
oneminute
Beginner
952 Views
Ok that makes sense, thanks for helping out.

Just for discussion:

I read an interesting way of exiting threads - To call QueueUserAPC on every thread, running a function that throws an "exit exception" when the thread enters an alertable wait, exiting threads cleanly and calling destructors. Could this be reasonably done in TBB? With tasks it seems hard to imagine calling a function on its threads.
0 Kudos
Andrey_Marochko
New Contributor III
952 Views
TBB threads do not use alertable wait functions, but even if they did, it would not helped much with cancellation, because TBB workers enter kernel mode wait only when there is no work available. Or do you envision some other usage of this mechanism?
0 Kudos
Reply