Generic stoppable interface

The thread message dispatcher's stop() method is an implementation of the x::stoppable interface. x::threadmsgdispatcherObj subclasses x::stoppableObj and implements stop by sendevent()ing a private class method that throws a x::stopexception.

A subclass of x::threadmsgdispatcherObj can override stop() and provide its own mechanism for stopping the execution thread.

When multiple threads are working together on the same task, sometimes it's desirable to coordinate their termination, as a group. Typical usage case would be having all threads terminate when any one of them terminates itself, or if a separate master thread terminates before they do. This is done by creating a group of stoppable objects.

class mythreadObj : public x::threadmsgdispatcherObj {

// ...
};

typedef x::ref<mythreadObj> mythread;

// ...

x::stoppable::base::group sgroup=x::stoppable::base::group::create();

mythread mainThread=mythread::create(), workerThread=mythread::create();

sgroup->add(mainThread);
sgroup->add(workerThread);

x::ref<x::obj> handle=x::ref<x::obj>::create();

sgroup->mcguffin(handle);

mythread extraThread=mythread::create();

sgroup->add(extraThread);

The stoppable group maintains a list of other objects that implement the stoppable interface. add() adds an object to the stoppable group. mcguffin() takes another object, and makes it a mcguffin that results in each object in the stoppable group having its stop() method invoked when the mcguffin goes out of scope.

In the above example, when mcguffin goes out of scope and gets destroyed, all objects in the stoppable group have their stop() invoked, including objects added to the group after a mcguffin's creation. In the above example, extraThread will also get stop()ed when the handle mcguffin goes out of scope.

More than one mcguffin can be tied to a stoppable group. When any mcguffin goes out of scope and destroyed, all objects in the stoppable group get stop()ed.

Once created, a stoppable group exists even if the x::stoppable::base::group reference-counted object goes out of scope. In the above example, even if sgroup goes out of scope, as long as one of its mcguffins still exists, somewhere, the mcguffin will do its duty and result in stop()age of object in the stoppable group.

If you want all the members of a stoppable group getting stop()ed when the stoppable group reference goes out of scope, make the stoppable group its own mcguffin. If you want the stoppable group stopped when any object in the stoppable group goes out of scope and gets destroyed, pass the object to both add() and mcguffin(). A stoppable group holds only weak references on the objects in the stoppable group; once any of them go out of scope naturally, and get destroyed, if it's also one of the group's mcguffins, all the other members of the stoppable group get stop()ed.