Mutex-protected objects

#include <x/ref.H>
#include <x/mpobj.H>

class msgObj;

// A container for pending messages

typedef std::list<x::ref<msgObj> > messages_t;

// Pending messages

x::mpcobj<messages_t> messages;

// A lock on the messages queue

typedef x::mpcobj<messages_t>::lock lock_t;

// ...

   lock_t lock(messages);


// ...

x::ref<msgObj> msg=({
   lock_t lock(messages);

   while (lock->empty())

   auto msg=lock->front();

The x::mpcobj template class implements a design pattern for a mutex-protected object, which attaches a std::mutex and a std::condition_variable. Access to the object requires obtaining a lock, which then may be used as a pointer to the locked object. The lock also provides access to the underlying condition variable, for signaling and waiting purposes.


These are not reference-counted classes. The underlying mutex-protected object instance must remain in scope as long as there are instances of instantiated locks.

An x::mpobj template class implements a mutex-protected object without a condition variable. Use it when a condition variable is not needed, only an object that's protected by a mutex.

The second optional parameter to the x::mpobj or the x::mpcobj template overrides std::mutex as the underlying mutex type.

Transferrable mutex locks

<url>x::mptobj</url> implements a mutex-protected object whose lock ownership is transferrable to a different execution thread.

#include <x/mpthreadlock.H>

typedef x::mptobj<locked_info_s> locked_info_t;

locked_info_t locked_info;

// ...

locked_info_t::lock original_lock{locked_info};

// Access something.

x::mpthreadlock<locked_info_s> preserver=original_lock.threadlock();

                           locked_info_t::lock new_lock{preserver};
                           // ...

Locks on mutex-protected objects must be constructed in automatic scope, and released by the same execution thread; but x::mpthreadlock provides a means of preserving a lock on the mutex-protected object after the original_lock goes away, preventing other locks from getting acquired. Its threadlock() method returns a preserver object, a reference-counted object that holds the lock (after the real lock goes away). The preserver gets passed to the new_lock's constructor, which now owns a real lock on the underlying object.


new_lock's constructor blocks until the original_lock goes out of scope and gets destroyed, if it still exists at the time the constructor gets invoked.

The preserver guarantees that the new_lock acquires the real lock as long as the original_lock no longer exists, even if other execution threads are attempting to acquire the real lock. The preserver "loses its mojo" after the lock ownership gets transferred to the new_lock and using it to construct another lock, afterwards, has no effect.