An x::destroy_callback_wait4
implements a way for a thread that destroys one object to stop, and then
wait for some other object to get destroyed too, presumably by another
thread.
A typical use case is when a thread constructs an object, and this
object constructs a reference to the second object. The first object
is considered to be the owner of the second object, but the second
object can also be used by other threads, and when the first object
goes out of scope and gets destroyed, it's necessary to also wait for
any other fleeting references to the second object to go out of scope
so that the second object gets destroyed too.
This is similar to a
guard object, except that the
guard object gets instantiated on the stack, and waits for all guarded
objects to get destroyed, when the guard object goes out of scope.
x::destroy_callback_wait4
is a reference
to a reference-counted object. Once
it gets created and installed, explicit references to the object are
no longer needed. A reference remains to it, since it's installed as a
destructor callback to some other object. Whichever thread ends up
destroying it, invokes the destructor callback, which then waits for
the second object to get destroyed, before proceeding.
#include <x/destroy_callback_wait4.H> #include <x/threads/run.H> class parentObj : virtual public x::obj { class childObj; public: parentObj() { } void start_child() { auto child=x::ref<childObj>::create(); addOnDestroy(x::destroy_callback_wait4::create(child)); x::run(child); } };
x::destroy_callback_wait4
's constructor
takes a reference to a reference-counted object.
Its destroyed
() method, when and if it gets
invoked, waits for the object's destruction, if it's not already
destroyed.
After the x::destroy_callback_wait4
gets
installed as a parent's destructor callback, once the parent object
goes out of scope and gets destroyed, if, previously, a child
object got started, parent's destruction automatically waits for the
child thread to exit, and for any other references to the child object
to also go out of scope, and get destroyed, before the destruction
of the parent object fully concludes.
Here's a slight variation on this theme:
x::run(child)->addOnDestroy(x::destroy_callback_wait4::create(child));
By installing a x::destroy_callback_wait4
destructor callback on the thread's return value object, this has
the effect of only waiting until the thread finishes execution.
With no other references to the thread return value object, it goes out
of scope and gets destroyed when the thread finishes, even if the child
thread object remains in scope due to other references.
Any thread where the last reference to the object that goes out of scope ends up invoking the destructor callback and waiting indefinitely for the other object to get destroyed, by some other thread. Threads and objects should be carefully designed, so that can actually happen, in pradtice.
Internally, x::destroy_callback_wait4
uses
x::destroy_callback
,
which is where it gets the class name from.