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

Scheduling something to happen after the current task load is finished?

Simon_G_
Beginner
388 Views

Disclaimer: I'm looking for an alternative to using mutex's or shared_ptr to solve this problem.

At the moment I'm using raw pointers in a tree model and the way my model works is that elements are put into a bin (and marked as such) before they are deleted. Once something is in the bin, there's no way to access it, so I'm wondering whether tbb provides any way that I can schedule the deletion such that once all the current tasks are finished, the bin's elements can be deleted.

This works because whilst I can't guarantee that the current tasks don't reference those elements, I can guarantee that any tasks created after that point won't be referencing those elements. Ideally I would like to not stop other tasks from starting. It's almost like I'm saying "When all the current tasks are finished (ignoring any tasks created after this point), run this function/delete this bin." 

I'm guessing this is way out of left field and not possible at all, but I thought I'd ask. 

0 Kudos
4 Replies
jimdempseyatthecove
Honored Contributor III
388 Views

Nest the top level task. Perform the cleanup after nested task completion. One easy way to do this is:

...
{ // scope
YourTree_t tree; // ctor creates empty tree
parallel_invoke(
[]() {
... your multi-task code building and using tree
} // end functor
); // end parallel_invoke
// here when enclosed task(s) complete
} // end scope (runs dtor on tree)

Jim Dempsey

0 Kudos
Simon_G_
Beginner
388 Views

Unfortunately it's not like that. Our model is long living, and has several algorithms which run over it (e.g. search for a particular word). The user modifies the model via a GUI which (on delete) will take elements out of the tree and put them on the redo stack (it also does the "marking" that I mentioned in my first post). So imagine someone pastes a copy of a whole bunch of elements in, then presses undo, it puts them on the redo stack. When the user now takes another action (e.g. inserting a new element) it deletes those elements from the redo stack as there's now way to get back to inserting those elements back into the model via redo.

So at THAT point I want to schedule the deletion of those objects such that any operations that are currently running (e.g. the word search) have to complete before we wipe them from memory. 

The reason I don't want to use mutex's and/or shared pointers is because the chance of this conflict occuring is very low - an operation has to run on a particular node (after it's done the check to see whether it's been removed from the model) for enough time for a user to undo an operation and then do something else so that it actually needs to delete the model elements. 

I saw somewhere that you could have a task_scheduler_observer or some such - could that help?

0 Kudos
Simon_G_
Beginner
388 Views

I've just read about hazard pointers for the first time (pretty new to lock free programming), which would totally solve my problem, but I think the scheduling design is actually better for a task based system which can make the assurances that I can (for starters it doesn't need to go and check all the hazard pointers before deleting things, it essentially knows how long to wait before it is safe to delete it).

If TBB doesn't have any inbuilt way of doing something like this, I think I can do it by implementing an atomic int in a Concurrency wrapper class which is a reference counter that essentially represents the "task set number". So when we run a task it takes a copy of the pointer to that int and increments the int, when that task finishes it decrements the int.

When we schedule the deletion of things we do the following:
* Take a copy of the pointer to the int
* Create a new int initialised to zero and give it to the Concurrency wrapper to give to all the tasks that it creates from there.
* Check to see if the original int is zero - if it is, all the tasks started before that swap over have finished, if it is not, we can't delete yet, so it yeilds or schedules to check again in some period of time.
* If we do two delete's in quick succession and the first one hasn't deleted yet, the second one needs to make sure the first one has also ended, so the delete code has to be a bit smart and keep a list of things waiting to be deleted and a list of "task set numbers" that need to be finished before it can safely delete. If deleting is always done from one thread (such as in my model) this is trivial.
 

0 Kudos
Simon_G_
Beginner
388 Views

I've done some more reading and it doesn't look like we can implement sceduled destruction of objects via the TBB API. Maybe this is something that Intel could explore for future revisions? Maybe it's white paper worthy... 
 

0 Kudos
Reply