Boost logo

Boost :

Subject: [boost] [thread|interprocess] Boost.Synchro: Towards a generic view of synchronization mechanisms
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2009-02-06 01:18:32


Hi,

Currently there are two libraries defining mutex, condition variables and locks in Boost (Boost.Thread and Boost.Interprocess), which have similar interfaces but with some differences. This has as consequence that we can not interchange them.

One of the reasons is that we are not working with concepts, and algorithms. Both boost::mutex and boost::interprocess_mutex are models of the same Lockable concept, but not because they share a common syntax but because they share a common semantics. Can we see a binary_semaphore as a Lockable? Well, usually a binary_semaphore will define operations such a post and wait, so binary_semaphore do no share the common syntax as boost::mutex and boost::interprocess_mutex. On the semantic side wait can be assimilated to lock and post to unlock.
By the way, there are also other syntactical differences between the Boost.Thread and Boost.Interprocess classes.

So how can we write gerenic code that can be used with every model of the concepts. The idea consist in switching from the OO paradigm to the functional paradigm. We found the same approach Boost.MPL and Boost.Fusion between others. So instead of requiring that a model of the concept Lockable defines the member functions lock and unlock, we require that the functional expressions lock(m) and unlock(m) are well founded.

A generic Synchro library can define a default implementation that forwards to the member function.

    namespace synchro {
        template <typename Lockable>
        void lock(Lockable& lockable) {
               return lockable.lock();
        }
    }

Now we can overload the lock function on a binary_semaphore as

    namespace synchro {
        void lock(binary_semaphore& sem) {
               return sem.wait();
        }
    }

Just another example for a class template anotherLockableModel that models the Lockable concept but that with acquire/release functions. We need to overload again the lock function.

    namespace synchro {
        template< typename T>
        void lock( anotherLockableModel<T>& lockable ) {
                    return lockable.acquire();
        }
    }

However, there are cases where overloads do not suffice (as described in N1295 - Partial specialization of function templates), and we need to use partial specialization of function templates. On compiler that do not support partial specialization of function templates we can use a workaround, that is, use partial specialization of class templates. The default implementation will now forward to a static function of a class which has forward to the member function

    namespace synchro {
        namespace partial_specialization_workaround {
            template< typename Lockable >
            struct lock {
                static void apply( Lockable& lockable ) {
                    return lockable.lock();
                }
            };
        }

        template <typename Lockable>
        void lock(Lockable& lockable) {
            return partial_specialization_workaround::lock<Lockable>::apply(lockable);
        }
    }

So now the user can partially specialize the class template partial_specialization_workaround::lock and define the apply function as needed:

    namespace synchro {
        namespace partial_specialization_workaround {
            template< typename T>
            struct lock <anotherLockableModel<T> >{
                static void apply( anotherLockableModel<T>& lockable ) {
                    return lockable.acquire();
                }
            };
        }
    }

Once we have all the Lockable operations defined in this way, and do the same for ConditionVariable, we can define in a generic way unique_lock, shared_lock and upgrade_lock that works with boost::shared_mutex as boost::interprocess::interprocess_upgradable_mutex. This could leverage these libraries to define its own locks classes.

Ion, Anthony, Boosters what do you think of applying this approach to get a generic Synchro library?
Should the partial_specialization_workaround be applied systematicaly or it complicates things?

Thanks,
Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk