A registration handler lock

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::updatelocks, but doesn't block other x::vipobj::handlerlocks. Multiple x::vipobj::handlerlocks 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.