[Patch] Clang: allow scoped_lockable to acquire multiple locks

Howard Hinnant howard.hinnant at gmail.com
Sun Aug 31 17:31:18 PDT 2014


On Aug 31, 2014, at 4:00 PM, Richard Smith <richard at metafoo.co.uk> wrote:

>> On Sat, Aug 30, 2014 at 9:53 PM, Ed Schouten <ed at 80386.nl> wrote:
>> Hi DeLesley,
>> 
>> First of all, thanks for your work on the thread annotations for
>> Clang! Impressed by how well they work, I decided to patch up
>> FreeBSD's pthread library to use these annotations by default.
>> 
>> http://lists.freebsd.org/pipermail/freebsd-toolchain/2014-August/001183.html
>> 
>> While experimenting with using these annotations in a C++ codebase, I
>> discovered that it's currently not possible to use these for
>> interlocking, as scoped_lockable does not support acquiring multiple
>> mutexes. Example:
>> 
>> class SCOPED_LOCKABLE DoubleGuard {
>>   DoubleGuard(Mutex* m1, Mutex* m2) EXCLUSIVE_LOCK_FUNCTION(m1, m2) {
>>     if (m1 == m2) {
>>       m1_ = m1;
>>       m2_ = nullptr;
>>       m1_->Lock();
>>     } else {
>>       if (m1 < m2) {
>>         m1_ = m1;
>>         m2_ = m2;
>>       } else {
>>         m1_ = m2;
>>         m2_ = m1;
>>       }
>>       m1_->Lock();
>>       m2_->Lock();
>>     }
>>   }
>> 
>>   ~DoubleGuard() UNLOCK_FUNCTION() {
>>     m1_->Unlock();
>>     if (m2_ != nullptr)
>>       m2_->Unlock();
>>   }
>> 
>>  private:
>>   Mutex* m1_;
>>   Mutex* m2_;
>> };
>> 
>> This class cannot be used, as it will cause a warning that the guard
>> object itself is locked twice. Attached is a patch to fix this. It
>> changes the lock path to always create exactly one FactEntry for
>> scoped lockables. Instead of having a single UnderlyingMutex, it now
>> uses a CapExprSet.
>> 
>> What are your thoughts on this change? Is it all right for me to commit this?
>> 
> Does this handle the variadic template case:
> 
> class SCOPED_LOCKABLE MultiGuard {
> public:
>   template<typename ...T> MultiGuard(T *...mutexes) EXCLUSIVE_LOCK_FUNCTION(mutexes...)
>     : m{mutexes...} {
>     std::sort(m.begin(), m.end());
>     for (Mutex *mut : m) mut->Lock();
>   }
>   ~MutexGuard() UNLOCK_FUNCTION() {
>     std::reverse(m.begin(), m.end());
>     for (Mutex *mut : m) : mut->Unlock();
>   }
> private:
>   std::vector<Mutex*> m;
> };

On locking multiple locks at once:

http://htmlpreview.github.io/?https://github.com/HowardHinnant/papers/blob/master/dining_philosophers.html

One should probably use std::lock for this, and if std::lock doesn’t have sufficiently high performance for you, you should submit a bug report.  The linked paper above is a fairly in-depth study of the performance of various algorithms.  The ordered solution (what is proposed above) does not have impressive performance.

Howard






More information about the cfe-commits mailing list