Index
The
x::vipobj
template instantiates a class that implements a
“very important object” design pattern.
A “very important object” is an object paired with a list of
callbacks.
The callbacks get invoked when the very important object gets
“modified”.
It's a very important object, after all, and everyone wants to
know when it changes, and what its new value is.
x::vipobj
implements an API of atomically
registers a new lambda callback, and gives it
the current value of the very important object, in a single operation,
as the callback's initial value.
A key attribute of a “very important object” is that the
notification mechanism must be consistent when a new lambda callback
gets registered at the same time that another thread updates the
very important object.
In this situation, one of two things will happen here.
Either the new lambda gets the modified value, or it
gets the original value of the very important object, then gets notified
with the modified value immediately afterwards.
These well-defined, thread-safe semantics provide a reliable
access mechanism that's somewhat more sophisticated than a
plain “read lock” and “write lock”
design.
The very important object design pattern uses four different locking
objects
that x::vipobj
exports as part of its
implementation.
Access to the very important object is thread-safe,
as long as these lock objects get
instantiated and used as per their documented interface.
The
x::vipobj
template instance
is not a
reference-counted.
object itself.
A x::vipobj
is typically not used directly,
but is usually a member of a larger (most likely a
reference-counted) class that exports a
high level API.
The API is implemented using
x::vipobj
lock objects, instantiated
in the right order.
Registering a lambda with a very important object returns a
x::callback
handle, which should be treated as a reference-counted handle for the
installed lambda.
There's no formal deregistration method for a
handler, just a registration mechanisms. The handler
callbacks remain registered until they go out of scope and get destroyed.
When a callback gets registered, as part of registration the callback gets optionally invoked with the current value of the very important object. The callback continues to be invoked whenever the very important object is modified, with the modified value. In this manner, each callback handler maintains a stable view of the very important object's value, as it gets modified by other threads, over time, starting with the time the handler was registered with the very important object.
#include <x::vipobj.H> class vipintvalue { public: int n; vipintvalue(int nValue=0); vipintvalue(const std::string &); }; typedef x::vipobj<vipintvalue> vip_t; vip_t vip;
x::vipobj
's constructor forwards its arguments
to the object's constructor.