I have an issue with TBB that makes my application crash systematically on exit.
I use automatic task_scheduler_init and sometimes spawn new tasks within tbb threads.
The culprit is when one of these tasks interacts with the Qt library, internally Qt initializes (even if not needed) a thread local object (using pthread), that must live at least as long as the QApplication object (because it uses method on it).
Basically, what happens is that TBB threads only really stop when the whole process is terminating. With their termination, the pthread local storage created by Qt is destroyed, however, the QApplication object of my application is long gone when the process actually exit.
Actually there's no workaround for me, the QApplication object is always destroyed before the actual handlers of the thread local storage are invoked.
This behavior happens only because I'm unable to join the threads spawned by tbb earlier. Is there any way to actually enforce the lifetime of TBB threads ?
I tried to control myself the lifetime of the task_scheduler_init object but it is in some cases unfeasible because of very complex inter-threads communication schemes which would require the thread that actually spawned a task to necessarily wait on it later on (which is a strong requirement!).
I'm aware of the following blog post regarding initialization/termination of the task scheduler https://software.intel.com/en-us/blogs/2011/04/09/tbb-initialization-termination-and-resource-management-details-juicy-and-gory
but it didn't help.
Anybody has a potential workaround or idea on how to fix this ?
By default task_scheduler_init does not wait termination of TBB workers.However, there is a preview functionality, called blocking_terminate (see https://www.threadingbuildingblocks.org/docs/help/hh_goto.htm?index.htm#reference/appendices/preview_features/task_scheduler_extensions.html), which might be helpful in your case. As far as I understand from your problem description, you need to make sure to call blocking terminate before destruction of QApplication object.
Thank you for your answer. Actually I found that function but its usage is almost impossible in my application:
Many threads are subject to use the tbb scheduler, even tbb workers themselves. In order to have blocking terminate working, I need to control the lifetime of task_scheduler_init and never have a thread use automatic initialization (because if I understand well it uses thread local storage and will have automatic deinitialization only when the thread exits).
Actually, this is where I'm having an issue: Since tbb workers are subject to use the scheduler themselves, how am I supposed to control the lifetime of a task_scheduler_init myself ? Prior to any call to tbb function or object I need to create a task_scheduler_init. Moreover I need to ensure that the task_scheduler_init on that thread lives as long as tbb calls are made. This gets complicated if I have a thread that i.e just wants to fire another task: I need a callback when the task ends on the very same thread to kill the task_scheduler_init object.
In most cases this is fine because I launch blocking concurrent algorithms such as parallel_for, so I can definitely kill the task_scheduler_init object right after all computations are done.
However this design is made difficult when I just want to enqueue a task without ever caring to receive a callback on the thread that fired it.
Currently to ensure that I can control blocking_terminate I put a breakpoint in tbb to ensure that auto terminate/initialized is never used.
To me there should be an easier way to control that, maybe by controling the lifetime of task_scheduler_init within tbb itself in a smarter way: i.e: deinit the task_scheduler on that thread when its finished computing anything. (could be optional).
Try to create first task_scheduler_init object just after instantiation of QApplication object and call blocking_terminate just before the destruction of that task_scheduler_init, which, in turn, is followed immediately by ~QApplication, all within the application master thread.