Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.
Announcements
The Intel sign-in experience has changed to support enhanced security controls. If you sign in, click here for more information.

VC++ Release Optimizations Breaking Code

oneminute
Beginner
220 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
Black Belt
220 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

11 Replies
RafSchietekat
Black Belt
220 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.
oneminute
Beginner
220 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 :)
RafSchietekat
Black Belt
220 Views
Don't make a task run a message handler: that's a thread's job.
oneminute
Beginner
220 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)
RafSchietekat
Black Belt
220 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, ...
oneminute
Beginner
220 Views
What is the best way to flag the program to exit from within the thread?
RafSchietekat
Black Belt
221 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.

oneminute
Beginner
220 Views
Would this work for both threads and tasks when they are used in the same application?
RafSchietekat
Black Belt
220 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.
oneminute
Beginner
220 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.
Andrey_Marochko
New Contributor III
220 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?
Reply