[thread] is there an interest on this unique_to_shared_mutex_adapter class?

Hi, boost::mutex is a model of Lockable but do not conforms to a SharedLockable, UpgradeLockable concepts. Do you think that we can make an adapter of boost::mutex to be a model of SharedLockable, UpgradeLockable or there is something I've missed? Consider the following situation: template <class SharedLockable> void f(SharedLockable&l) const { /*< externally locked generic const function>*/ boost::shared_lock<Lokable> lock(smtx); // ... some read operations } // elsewhere boost::mutex mtx; /*< the external user prefer to use a mutex and not a shared_mutex >*/ // { shared_lockable_adapter smtx(mtx); /*< mtx must be adapted to a shared_mutex >*/ f(smtx); /*< to call f without compiler errors >*/ //.. } Do you know a simple way to achieve this? Do you think this adapter could be of general use? The class shared_lockable_adapter can be defined as follows: template <typename Lockable> class shared_lockable_adapter { shared_lockable_adapter(Lockable& mtx): mtx_(mtx) {} ~shared_lockable_adapter() {} void lock_shared() {mtx_.lock();} void unlock_shared() {mtx_.unlock();} bool try_lock_shared() { return mtx_.try_lock();} void lock() {mtx_.lock();} void unlock() {mtx_.unlock();} bool try_lock() { return mtx_.try_lock();} // other functions .... private: Lockable& mtx_; }; Comments? _____________________ Vicente Juan Botet Escriba

vicente.botet wrote:
template <typename Lockable> class shared_lockable_adapter { shared_lockable_adapter(Lockable& mtx): mtx_(mtx) {} ~shared_lockable_adapter() {} void lock_shared() {mtx_.lock();} void unlock_shared() {mtx_.unlock();} bool try_lock_shared() { return mtx_.try_lock();} void lock() {mtx_.lock();} void unlock() {mtx_.unlock();} bool try_lock() { return mtx_.try_lock();} // other functions .... private: Lockable& mtx_; };
So this is a trivial adapter that makes a shared mutex that can't actually be shared. It would also be possible, I think, to make an adapter that actually creates a shared mutex from a normal one. I've never had to write a read/write mutex but I guess that this is how they are implemented internally. There are various usage scenarios. For example, I may have a generic algorithm that really needs a shared lock that can be shared, i.e. it creates threads that must run concurrently. If I concept-check that the passed mutex is a SharedLockable, but it's actually your adaptor, I'll get a runtime deadlock. Maybe we need some more fine-grained concepts to express these requirements. Certainly it would help if algorithms could work with both shared and non-shared mutexes without extra effort. I'm not yet aware of much generic code that uses mutexes and lock concepts. No doubt we will learn more as that code appears. Phil.

Hi Phil, ----- Original Message ----- From: "Phil Endecott" <spam_from_boost_dev@chezphil.org> To: <boost@lists.boost.org> Sent: Friday, May 09, 2008 7:06 PM Subject: Re: [boost] [thread] is there an interest onthis unique_to_shared_mutex_adapter class?
vicente.botet wrote:
template <typename Lockable> class shared_lockable_adapter { shared_lockable_adapter(Lockable& mtx): mtx_(mtx) {} ~shared_lockable_adapter() {} void lock_shared() {mtx_.lock();} void unlock_shared() {mtx_.unlock();} bool try_lock_shared() { return mtx_.try_lock();} void lock() {mtx_.lock();} void unlock() {mtx_.unlock();} bool try_lock() { return mtx_.try_lock();} // other functions .... private: Lockable& mtx_; };
So this is a trivial adapter that makes a shared mutex that can't actually be shared.
Yes you are right, you will not allow shared owneship, but that allows to use generic functions that works for a ExclusiveLockable and than can perform better for a SharedLocable mutex, and it is up to the user to choose between an adaptation of mutex or a shared_mutex. If the performances are obtained using the SharedLockable extensions the function must be defined in terms of this concept. Conside an application that must use a lot of some classes and algorithms and preserv a transaction behaviour, so some kind of common mutex will be used to synchonize externally all this classes and algorithms. Supose that some classes or algorithms have been templated with a SharedLockable. Even if the SharedLockable classes and algorithms can perform better with shared_mutex when isolated, this do not implies that the whole application will perform better. This is where the shared_lockable_adapter can be used. All this depends on the user application.
It would also be possible, I think, to make an adapter that actually creates a shared mutex from a normal one. I've never had to write a read/write mutex but I guess that this is how they are implemented internally.
The better adapter will be to take a shared_mutex directly as it can be used directly on contexts waiting a ExclusiveLockable.
There are various usage scenarios. For example, I may have a generic algorithm that really needs a shared lock that can be shared, i.e. it creates threads that must run concurrently. If I concept-check that the passed mutex is a SharedLockable, but it's actually your adaptor, I'll get a runtime deadlock. Maybe we need some more fine-grained concepts to express these requirements.
Surely you are right. The adaptor will limit the concurrence. Only if the thread taking the shared-lock (exclusive lock with the adaptor) needs some kind of active communication from the other thread while the mutex is locked, we will have dead lock. For the other cases, the adapter works as expected. I don't know if your example is a particular case or a common one. I use to do this way and I have never fall in a deadlock to the point that I thought that a sharable lock was substituable by a exclusive lock. Evidently I was completly wrong, we can not substitute in any semantic context. But it works on a lot of situations. This do not means that all the algorithms expecting a SharedLockable will result on a deadlock with the adapter of a ExclusiveLockable mutex, very often the choice of a SharedLockable or a ExclusiveLockable is a matter of efficiency. How to express that is another history. Maybe we need to state that the parameter is a model of a SharedLocable or a shared_lockable_adapter of an ExclusiveLockable. But this seams yet to specific, what if the function works as expected for another adaptation of another concept. Been forced to define two functions with the same algorithms (copy/paste+rename) that differ only on the name of the functions called do not seams better. This is pure theory, we are not talking of a particular function, but IMHO we need to define the function working for model of the SharedLocable concept, and add some textual semantic constraints. shared_lockable_adapter<model of ExclusiveLockable> is a model of SharedLocable that could or not satisfy the semantic constraints. It is up to the developer to use it or not. I 'm sure that this is not the first time we have something like this. Some thoughts? If the requirements you are talking off are related to the semantics of the operations, you are right, the current C++ concepts wouldn't be of any help, concepts do not capture semantics. Which kind of more fine-grained concepts are you referring?
Certainly it would help if algorithms could work with both shared and non-shared mutexes without extra effort.
Note that all the algoritms that works today with exclusive mutexes, can be refactored to use shared-locks instead of exclusive locks on the reading blocks. All these algorithms will work with both shared and exclusive mutexes without any extra effort.
I'm not yet aware of much generic code that uses mutexes and lock concepts. No doubt we will learn more as that code appears.
You are right, there is not too much generic code that let the user the synchronization context, most are not thread safe, and delegate this responsability to the user. I supose that this kind of code will be more frequent than we use to. We can see the work on lock-free algorithms and containers. Thread safety starts to be a must as it was exception safety some years ago. The multi-core/multi-processor/grid architectures push the software to go in this direction, parallelism, parallelism ... and even if this will be more complex without the good abstractions and there will be a long way to get them, the result will be more close to our thinking. Sorry for my english and thanks for your pertinency Vicente

"Phil Endecott" <spam_from_boost_dev@chezphil.org> writes:
vicente.botet wrote:
template <typename Lockable> class shared_lockable_adapter { shared_lockable_adapter(Lockable& mtx): mtx_(mtx) {} ~shared_lockable_adapter() {} void lock_shared() {mtx_.lock();} void unlock_shared() {mtx_.unlock();} bool try_lock_shared() { return mtx_.try_lock();} void lock() {mtx_.lock();} void unlock() {mtx_.unlock();} bool try_lock() { return mtx_.try_lock();} // other functions .... private: Lockable& mtx_; };
So this is a trivial adapter that makes a shared mutex that can't actually be shared.
I'm not sure this is such a good idea, as it wouldn't really be shareable.
It would also be possible, I think, to make an adapter that actually creates a shared mutex from a normal one. I've never had to write a read/write mutex but I guess that this is how they are implemented internally.
It's a bit more complicated than that. boost::shared_mutex is implemented on top of boost::mutex and boost::condition_variable for pthreads: take a look. Anthony -- Anthony Williams | Just Software Solutions Ltd Custom Software Development | http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Friday 30 May 2008 06:40 am, Anthony Williams wrote:
It would also be possible, I think, to make an adapter that actually creates a shared mutex from a normal one. I've never had to write a read/write mutex but I guess that this is how they are implemented internally.
It's a bit more complicated than that. boost::shared_mutex is implemented on top of boost::mutex and boost::condition_variable for pthreads: take a look.
Hmm, so it looks like it would be straightforward to convert the pthread implementation of shared_mutex into an adapter that can convert an arbitrary mutex type (conforming to the boost.thread Lockable concept) into a shared mutex, by turning its boost::mutex into a template type? -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFIQATi5vihyNWuA4URAtDSAJ44PVA1aGFm8m8StlSXukwUi3nw2gCfQnkm p0RpVNNKfpnvaA0EHT1CDj0= =DFq3 -----END PGP SIGNATURE-----

Frank Mori Hess <frank.hess@nist.gov> writes:
On Friday 30 May 2008 06:40 am, Anthony Williams wrote:
It would also be possible, I think, to make an adapter that actually creates a shared mutex from a normal one. I've never had to write a read/write mutex but I guess that this is how they are implemented internally.
It's a bit more complicated than that. boost::shared_mutex is implemented on top of boost::mutex and boost::condition_variable for pthreads: take a look.
Hmm, so it looks like it would be straightforward to convert the pthread implementation of shared_mutex into an adapter that can convert an arbitrary mutex type (conforming to the boost.thread Lockable concept) into a shared mutex, by turning its boost::mutex into a template type?
No, I don't think so. The internal mutex within shared_mutex is only locked within the member functions, and it is required to be exclusive in order to protect the internal data. When you call shared_lock, the only sense in which this thread holds a mutex is that the internal state of the shared_mutex reflects that. Anthony -- Anthony Williams | Just Software Solutions Ltd Custom Software Development | http://www.justsoftwaresolutions.co.uk Registered in England, Company Number 5478976. Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL
participants (4)
-
Anthony Williams
-
Frank Mori Hess
-
Phil Endecott
-
vicente.botet