vip_t::handlerlock hl(vip); auto callback1=hl->install_front([] (const vipintvalue &v) { // ... }); vipintvalue val=*vip_t::readlock(vip); auto callback2=hl->install_back([] (const vipintvalue &v) { // ... }, val);
Use x::vipobj::handlerlock
for registering a lambda handler for a very important object.
Instantiating a x::vipobj::handlerlock
blocks
x::vipobj::updatelock
s, but doesn't block
other x::vipobj::handlerlock
s. Multiple
x::vipobj::handlerlock
s can get instantiated
concurrently.
install_front
() registers a new lambda handler,
and adds it to the front of the list of any existing handlers.
install_back
() adds it to the back.
They each return a \ref callback "callback handle" that wrapped the
lambda into a reference-counted object. The very important object
keeps a weak list of all registered lambdas, and
notify
() invokes them, in order.
Both install_front
() and
install_back
() take an optional value of the
very important object. Typically one would use a read lock to obtain
the value, but the value can come from anywhere. If the optional
value is given, the newly-registered lambda gets invoked immediately,
receiving this value as supposedly the initial value of the very
important object.
The second example acquires a read lock, copies the value of the
very important object, and releases the read lock.
The second parameter, the supposed current value, is optional. If not specified, the newly installed callback does not get invoked after installation.
The second example above, releases the read lock before installing the
new lambda.
It's permissible to acquire, and hold, read or write locks, while
invoking install
(). Of course, that affects the
callback handler's own access to the very important object. Additionally,
nothing prevents other threads from acquiring their own read and write
locks, and accessing the very important object while the handler lock
remains in scope.
The handler lock only blocks update locks. After the handler lock
goes out of scope, official changes to the very important object get
reported to the installed handler by instantiating new update locks and
invoking their notify
() methods.
A different mechanism registers a callback that's attached to an existing object, rather than returning a mcguffin:
typedef x::ref<;my_classObj> my_class_t; auto my_class=my_class_t::create(); vip_t::handlerlock hl(vip); auto current_value=*vip_t::readlock(vip); auto callback1=hl->attach_front(my_class, [] (const my_class_t &my_class, const vipintvalue &v) { // ... }, current_value);
The first parameter to
attach_front
() or
attach_back
() is some existing reference-counted
object. The second parameter is a lambda to be registered as a callback.
The third, required parameter, is the initial value of the very important
object that gets reported to the callback lambda.
attach_front
() and
attach_back
() do not return a mcguffin for the
registered callback. Rather, the callback lambda remains registered as
long as the object passed as the first parameter exists. When the value
of the very important object gets updated, the lambda gets invoked.
The lambda's first parameter is the original object, and the second
parameter is the initial or the new value of the very important object.
This is the typical approach to have an existing object's method get invoked when the very important object's value changes. The lambda simply invokes the object's method, forwarding the value parameter to it.