TBB tasks are non preemptive, i.e. if a task started to execute, it will run to completion before the thread running it can start another task.
The way to set a sort of priority to a TBB task is to change its depth. There is a couple of methods in class task to do that. Increasing task depth makes the task to be taken for execution earlier, but it also makes it (and its descedants) be considered for stealing later than tasks with lesser depth. So it might not work ideally for you.
In the recent developer updates, there is a prototype of the new functionality that allows cancelling execution of a particular group of tasks. Soon we will release an updated version of it that should be more close to the final one. If your background tasks can be organized in a way that their execution can be safely cancelled and then a new invocation of those tasks can resume from the place where stopped, you might consider this technique. In case of more questions about it, please ask in a couple of weeks.
It sounds like a perfectly reasonable approach, and similar to ideas I've seen before to activate TBB only when there's work to do to maximize the advantage of spin locks without leaving things spinning when there's no work to do.
Have you collected any data on scalability?
Perhaps I was overlooking some details, but I thought I understood J. Muffat's explanation. At the core is the use of a pair of filters, the serial input filter that gets called when the "background work" thread initiates the pipeline and passes the lump of decompression work along to the parallel filter, probably as a continuation task. While that thread occupies itself with work, the TBB task scheduler dispatches another pool thread to the serial input task. If semTodo indicates the availability of more work, the new thread repeats the process, stacking parallelthreads doing decompression work. If at the dispatch of any input task it should discover nothing waiting at semTodo, it could wait for semDone, or even spin, alternately checking both as suggested in the text above. Checking both would provide a bit of hysteresis for covering bursty incoming work. When both are empty, the current input filter returns NULL and the pipeline shuts down.
There may be some additional details to bulletproof the process. I'd imagine semDone to be more of an atomic reference count than a full blown semaphore, and probably would get incremented by the input filter and decremented by the processing filter. And there may be some additional details to ensure the background work thread doesn't interfere with semTodo while the sequence of input filters are active, but I do not see any holes in the basic process. Perhaps I'm missing something as well?