[rfc] thread-safe monitor objects

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I've written a couple small classes to better support the creation of monitor objects, see: http://www.comedi.org/projects/libpoet/boostbook/doc/boostbook/html/poet/mon... I'd like to know if there's any interest in adding something like this to boost, and also looking for ideas on how to improve my implementation. It works via a monitor_ptr class, which is like a shared_ptr with automatic mutex locking, plus an (optional) monitor_base class that lets classes managed by monitor_ptr do wait/notifies on a condition. I put it in libpoet, but the monitor_ptr and monitor_base stuff really only depends on boost. - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFHPIjA5vihyNWuA4URAlXaAJ0YmyV2ZgBTOc1Okn29aHP3Of7R0gCfUrf3 6nVluGNuKFCEy59ukjQcbMY= =u0Sq -----END PGP SIGNATURE-----

Frank Mori Hess wrote:
I've written a couple small classes to better support the creation of monitor objects, see:
http://www.comedi.org/projects/libpoet/boostbook/doc/boostbook/html/poet/mon...
Interesting...
I'd like to know if there's any interest in adding something like this to boost, and also looking for ideas on how to improve my implementation.
Since I have something similar in my own code I would certainly be interested in a quick monitor utility. But...
It works via a monitor_ptr class, which is like a shared_ptr with automatic mutex locking, plus an (optional) monitor_base class that lets classes managed by monitor_ptr do wait/notifies on a condition.
I wouldn't, and I didn't in my implementation, tie it directly to the pointer concept. In most uses I've seen, i.e. my code, the monitored object is not dynamically allocated and rather is embedded in a class. That is I find myself converting existing class members to monitored, rather than converting to a pointer (plus dynamic allocation). For example: struct A { monitor<int> count; int get_count() const; void set_count(int); }; I also prefer manual RAII locking as it makes it clear the locked scopes, and hence easier to debug locking problems. For example: int A::get_count() const { monitor<int>::scoped_lock count_(this->count); return *count_; } void A::set_count(int c) { monitor<int>::scoped_lock count_(this->count); *count_ = c; } Note, I was lazy and opted for pointer semantics for the scoped_lock since I wanted very simple code. But reference/value semantics might be more appropriate. Especially since one might want a "monitor< auto_ptr<A> >", for example. HTH. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Thursday 15 November 2007 23:57 pm, Rene Rivera wrote:
I wouldn't, and I didn't in my implementation, tie it directly to the pointer concept. In most uses I've seen, i.e. my code, the monitored object is not dynamically allocated and rather is embedded in a class. That is I find myself converting existing class members to monitored, rather than converting to a pointer (plus dynamic allocation). For example:
struct A { monitor<int> count;
int get_count() const; void set_count(int); };
I assume a monitor<T> requires that T be copy-constructible? I guess that's not a big deal, since T could be made a pointer type, or a boost::ref. I would have liked to have separated out the smart_ptr from the monitor functionality but didn't see a really good way to do so in keeping with the pointer concept. It isn't absolutely required to do dynamic allocation of the "owned" object though, since you can create a monitor_ptr from a shared_ptr with a null deleter, which can in turn be created from a pointer to the stack.
I also prefer manual RAII locking as it makes it clear the locked scopes, and hence easier to debug locking problems. For example:
I like being able to use the monitor_ptr directly without having to explicitly create another object first. However, I can certainly imagine cases where being able to make multiple member function calls without releasing the lock in between would be convenient. It wouldn't be hard to add this, a monitor_ptr::scoped_lock would basically be a monitor_call_proxy with a public constructor. Also, if it provided wait/notify functions, it would be possible to extend a monitor using free functions with full access to the monitor functionality. Actually, with a monitor_ptr::scoped_lock the internal boost::condition might be dropped entirely. The monitor_base class could just provide a reference to the current scoped_lock and a derived class could pass the scoped_lock to the wait() functions of its own conditions (of which it could have more than one). I don't know, maybe I am too attached to the idea of using monitor_ptr directly as a smart pointer. A shared ownership pointer seems natural in a way though, since multiple pointers/references to a single monitor object will inevitably be passed around to multiple threads.
Note, I was lazy and opted for pointer semantics for the scoped_lock since I wanted very simple code. But reference/value semantics might be more appropriate. Especially since one might want a "monitor< auto_ptr<A> >", for example.
You mean make it act like a "smart reference" instead of a "smart pointer"? I don't know how to do that. The way operator->() works must have been designed to support smart pointers, but operator.() isn't overloadable at all? Maybe some kind of reflection library could do the magic? The monitor<auto_ptr<A> > case seems workable if your scoped_lock class has an explicit get() function that returns the underlying pointer (in this case a auto_ptr<A>*). - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD4DBQFHPbAw5vihyNWuA4URAiuAAJY9CZGdwL0jDrYNBuhhnL73/bDSAJ0dHeyz 4xiGlHzVlVNTfRgBL3yBWw== =t9+i -----END PGP SIGNATURE-----
participants (2)
-
Frank Mori Hess
-
Rene Rivera