C+11のmutex、lock、condition variableは分析を実現します.


本論文で解析したのは、llvm libc++の実現である.http://libcxx.llvm.org/
C+11の各種mutex、lockオブジェクトは、実際にはposixのmtex、conditionのパッケージです.でも、中にはたくさんの細かいところがあります.勉強になります.
std:mutex
まず次のstdを見にきます.:mutex:
カバンが一つ増えました.mutex同前m_,簡単です.各関数は何をすればいいですか?
class mutex
{
    pthread_mutex_t __m_;

public:
     mutex() _NOEXCEPT {__m_ = (pthread_mutex_t)<strong>PTHREAD_MUTEX_INITIALIZER</strong>;}
     ~mutex();
private:
    mutex(const mutex&);// = delete;
    mutex& operator=(const mutex&);// = delete;
public:
    void lock();
    bool try_lock() _NOEXCEPT;
    void unlock() _NOEXCEPT;

    typedef pthread_mutex_t* native_handle_type;
    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
};

mutex::~mutex()
{
    pthread_mutex_destroy(&__m_);
}

void mutex::lock()
{
    int ec = pthread_mutex_lock(&__m_);
    if (ec)
        __throw_system_error(ec, "mutex lock failed");
}

bool mutex::try_lock() _NOEXCEPT
{
    return pthread_mutex_trylock(&__m_) == 0;
}

void mutex::unlock() _NOEXCEPT
{
    int ec = pthread_mutex_unlock(&__m_);
    (void)ec;
    assert(ec == 0);
}
三種類のロック状態:std:defer_ロック、std:try_to_ロック、std:adopt_ロック
この3つは、いくつかのパッケージにロックがかかっている状態を示すためのものです.
std:defer_ロックはまだ取れていません.
std::try_to_ロックは、パッケージ構造の時にロックを取ってみます.
std::adopt_ロック、使用者はロックを獲得しました.
この三つのものは、実は偏特化に使われています.三つの空いているstructです.
struct  defer_lock_t {};
struct  try_to_lock_t {};
struct  adopt_lock_t {};
constexpr defer_lock_t  defer_lock  = defer_lock_t();
constexpr try_to_lock_t try_to_lock = try_to_lock_t();
constexpr adopt_lock_t  adopt_lock  = adopt_lock_t();
下のコードの中で、この三つのものはどうやって使うかが見えます.
std:lock_gard
このクラスが重要です.私たちが本当にロックを使う時、ほとんどはこれを使います.
このクラスは実は簡単です.
コンストラクタでmuttext.lock()を呼び出し、構文関数でmuttex.unlock()関数を呼び出しました.
C++は関数に異常があると、スコープ内の変数の解析関数を自動的に呼び出すので、std:lock_を使います.gurardは異常時に自動的にロックを解除することができます.これはなぜmutexの関数を直接使用しないでください.std:lock_グアードのせいです.
template <class _Mutex>
class lock_guard
{
public:
    typedef _Mutex mutex_type;
private:
    mutex_type& __m_;
public:
    explicit lock_guard(mutex_type& __m)
        : __m_(__m) {__m_.lock();}
    lock_guard(mutex_type& __m, adopt_lock_t)
        : __m_(__m) {}
    ~lock_guard() {__m_.unlock();}
private:
    lock_guard(lock_guard const&);// = delete;
    lock_guard& operator=(lock_guard const&);// = delete;
};
注意、std::lock_Gurardの二つのコンストラクタは、muttexのみを伝達するとコンストラクタのときにmut.lock()を呼び出してロックを得る.
adopt_を伝えたらロックtの場合は、使用者がロックを持っていることを説明しますので、もうロックを獲得しようとしません.
std:unique_ロック
unique_ロックは実際には包装類で、uniqueと名付けられています.std:lock関数と区別して使います.注意して、もう一つownsが増えました.ロック関数とrelease()関数は、std:lock関数で使用されます.
ownsロックがあるかどうかを判定するためのロック関数.
release()関数はロックに対する関連を放棄して、構造を分析する時、unlockロックに行くことはできません.またunique_を見てくださいロックの実現によって、上の3つのタイプが偏特化用に使われていることが分かります.
template <class _Mutex>
class unique_lock
{
public:
    typedef _Mutex mutex_type;
private:
    mutex_type* __m_;
    bool __owns_;

public:
    unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
    explicit unique_lock(mutex_type& __m)
        : __m_(&__m), __owns_(true) {__m_->lock();}
    unique_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
        : __m_(&__m), __owns_(false) {}
    unique_lock(mutex_type& __m, try_to_lock_t)    //   
        : __m_(&__m), __owns_(__m.try_lock()) {}
    unique_lock(mutex_type& __m, adopt_lock_t)     //   
        : __m_(&__m), __owns_(true) {}
    template <class _Clock, class _Duration>
        unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
            : __m_(&__m), __owns_(__m.try_lock_until(__t)) {}
    template <class _Rep, class _Period>
        unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
            : __m_(&__m), __owns_(__m.try_lock_for(__d)) {}
    ~unique_lock()
    {
        if (__owns_)
            __m_->unlock();
    }

private:
    unique_lock(unique_lock const&); // = delete;
    unique_lock& operator=(unique_lock const&); // = delete;

public:
    unique_lock(unique_lock&& __u) _NOEXCEPT
        : __m_(__u.__m_), __owns_(__u.__owns_)
        {__u.__m_ = nullptr; __u.__owns_ = false;}
    unique_lock& operator=(unique_lock&& __u) _NOEXCEPT
        {
            if (__owns_)
                __m_->unlock();
            __m_ = __u.__m_;
            __owns_ = __u.__owns_;
            __u.__m_ = nullptr;
            __u.__owns_ = false;
            return *this;
        }

    void lock();
    bool try_lock();

    template <class _Rep, class _Period>
    bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
    template <class _Clock, class _Duration>
    bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);

    void unlock();
    void swap(unique_lock& __u) _NOEXCEPT
    {
        _VSTD::swap(__m_, __u.__m_);
        _VSTD::swap(__owns_, __u.__owns_);
    }
    mutex_type* release() _NOEXCEPT
    {
        mutex_type* __m = __m_;
        __m_ = nullptr;
        __owns_ = false;
        return __m;
    }
    bool owns_lock() const _NOEXCEPT {return __owns_;}
    operator bool () const _NOEXCEPT {return __owns_;}
    mutex_type* mutex() const _NOEXCEPT {return __m_;}
};
std:lockとstd:try_ロック関数の上にあるのはすべてクラスのオブジェクトです.この二つは関数です.
std:lockとstd:try_ロック関数は複数のロックを同時に使用する場合、デッドロックを防止するために使用されます.これは実際に重要です.手書きコードで複数のロックの同期問題を処理していますので、間違えやすいです.
注意するのはstd::try_ロック関数の戻り値:
成功したら-1を返します.
失敗した場合、いくつかの鍵を返しましたが、成功しませんでした.0でカウントを開始します.
まず二つの鍵しかない場合、コードは簡単に見えるが、中には大きな文章があります.
template <class _L0, class _L1>
void
lock(_L0& __l0, _L1& __l1)
{
    while (true)
    {
        {
            unique_lock<_L0> __u0(__l0);
            if (__l1.try_lock())  //    l0,     l1
            {
                __u0.release();   //l0 l1     ,  unique_lock       l0,     release()  ,     l0 。
                break;
            }
        }//      l0,l1  ,     l0。
        sched_yield();  //                  ,CPU         
        {
            unique_lock<_L1> __u1(__l1); //         l1  ,          l1,          l1(          ,      )
            if (__l0.try_lock())
            {
                __u1.release();
                break;
            }
        }
        sched_yield();
    }
}
template <class _L0, class _L1>
int
try_lock(_L0& __l0, _L1& __l1)
{
    unique_lock<_L0> __u0(__l0, try_to_lock);
    if (__u0.owns_lock())
    {
        if (__l1.try_lock()) //  try_lock      ,        
        {
            __u0.release();
            return -1;
        }
        else
            return 1;
    }
    return 0;
}
上のロック関数は試しにデッドロックを防止しました.上は2つのロックの場合、複数のパラメータの場合は?
先にstdを見にきます.:try_ロック関数の実装:
中は再帰的にtry_を呼び出した.ロック関数自体は、すべてのロックが成功すれば、順次unique(u)をすべて取得します.ロックは全部リリースされます.
失敗があれば、失敗の回数をカウントし、最終的に戻ってきます.
template <class _L0, class _L1, class _L2, class... _L3>
int
try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
{
    int __r = 0;
    unique_lock<_L0> __u0(__l0, try_to_lock);
    if (__u0.owns_lock())
    {
        __r = try_lock(__l1, __l2, __l3...);
        if (__r == -1)
            __u0.release();
        else
            ++__r;
    }
    return __r;
}
マルチパラメータのstd:ロックの実装:
template <class _L0, class _L1, class _L2, class ..._L3>
void
__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
{
    while (true)
    {
        switch (__i)  //__i                   , 0    
        {
        case 0:   //      ,__i 0
            {
                unique_lock<_L0> __u0(__l0);
                __i = try_lock(__l1, __l2, __l3...);
                if (__i == -1)  //   l0  ,              ,         ,   unique_lock release,   
                {
                    __u0.release();
                    return;
                }
            }
            ++__i;  //  __i           ,    try_lock(__l1,__l2__l3,...)  l1   ,     +1,            ,         。
            sched_yield();
            break;
        case 1:   //      l1  ,      l1。
            {
                unique_lock<_L1> __u1(__l1);    
                __i = try_lock(__l2, __l3..., __l0);   //     l0    。       l1,         。
                if (__i == -1)
                {
                    __u1.release();
                    return;
                }
            }
            if (__i == sizeof...(_L3) + 1)   //   l0      ,    l0    。             l0,       l0    。
                __i = 0;
            else
                __i += 2; //  __i           ,    try_lock(__l2,__l3..., __l0)  l2   ,     +2
            sched_yield();
            break;
        default:
            __lock_first(__i - 2, __l2, __l3..., __l0, __l1);    //      l2   ,  __i  2。
            return;
        }
    }
}

template <class _L0, class _L1, class _L2, class ..._L3>
inline _LIBCPP_INLINE_VISIBILITY
void
lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
{
    __lock_first(0, __l0, __l1, __l2, __l3...);
}
マルチパラメータのstdが見られます.ロックの実現は以下の通りです.
まずロックを取ってからstdを呼び出します.ロックは残りのロックを取りに行きます.失敗したら、次に失敗した鍵を取ります.
上のプロセスを繰り返して、すべてのロックを成功裏に取得します.
上のアルゴリズムは比較的巧みな方法でパラメータの回転を実現した.
std:timed_mutex
std:timed_mutex  内部にmutexとconditionが封入されています.このように二つの関数で使えます.try_ロックfor try(u)ロックuntil 
実はposixのmutexとconditionの包装です.
class timed_mutex
{
    mutex              __m_;
    condition_variable __cv_;
    bool               __locked_;
public:
     timed_mutex();
     ~timed_mutex();
private:
    timed_mutex(const timed_mutex&); // = delete;
    timed_mutex& operator=(const timed_mutex&); // = delete;
public:
    void lock();
    bool try_lock() _NOEXCEPT;
    template <class _Rep, class _Period>
        _LIBCPP_INLINE_VISIBILITY
        bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
            {return try_lock_until(chrono::steady_clock::now() + __d);}
    template <class _Clock, class _Duration>
        bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
    void unlock() _NOEXCEPT;
};

template <class _Clock, class _Duration>
bool
timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
{
    using namespace chrono;
    unique_lock<mutex> __lk(__m_);
    bool no_timeout = _Clock::now() < __t;
    while (no_timeout && __locked_)
        no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
    if (!__locked_)
    {
        __locked_ = true;
        return true;
    }
    return false;
}
std:recursive_muttexとstd:recursive_timed_mutex
この二つは実際はstd:mutexとstd:timed_mutexのrecursiveモードの実現、すなわちロックされた取得者は、ロック関数を複数回呼び出すことができる.
posix mtexのrecursive mtexと同じです.
次のstdを見てください.:recursive_mutexの構造関数は分かります.
recursive_mutex::recursive_mutex()
{
    pthread_mutexattr_t attr;
    int ec = pthread_mutexattr_init(&attr);
    if (ec)
        goto fail;
    ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    if (ec)
    {
        pthread_mutexattr_destroy(&attr);
        goto fail;
    }
    ec = pthread_mutex_init(&__m_, &attr);
    if (ec)
    {
        pthread_mutexattr_destroy(&attr);
        goto fail;
    }
    ec = pthread_mutexattr_destroy(&attr);
    if (ec)
    {
        pthread_mutex_destroy(&__m_);
        goto fail;
    }
    return;
fail:
    __throw_system_error(ec, "recursive_mutex constructor failed");
}
std::cv_status
これはconditionが戻ってくるのを待っている状態を表すもので、上の3つがロックの状態を表すものと同じです.
enum cv_status
{
    no_timeout,
    timeout
};
std::condition_variable
posix condition variableを包装しました.
class condition_variable
{
    pthread_cond_t __cv_;
public:
    condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
    ~condition_variable();
private:
    condition_variable(const condition_variable&); // = delete;
    condition_variable& operator=(const condition_variable&); // = delete;
public:
    void notify_one() _NOEXCEPT;
    void notify_all() _NOEXCEPT;

    void wait(unique_lock<mutex>& __lk) _NOEXCEPT;
    template <class _Predicate>
        void wait(unique_lock<mutex>& __lk, _Predicate __pred);

    template <class _Clock, class _Duration>
        cv_status
        wait_until(unique_lock<mutex>& __lk,
                   const chrono::time_point<_Clock, _Duration>& __t);

    template <class _Clock, class _Duration, class _Predicate>
        bool
        wait_until(unique_lock<mutex>& __lk,
                   const chrono::time_point<_Clock, _Duration>& __t,
                   _Predicate __pred);

    template <class _Rep, class _Period>
        cv_status
        wait_for(unique_lock<mutex>& __lk,
                 const chrono::duration<_Rep, _Period>& __d);

    template <class _Rep, class _Period, class _Predicate>
        bool
        wait_for(unique_lock<mutex>& __lk,
                 const chrono::duration<_Rep, _Period>& __d,
                 _Predicate __pred);

    typedef pthread_cond_t* native_handle_type;
    _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}

private:
    void __do_timed_wait(unique_lock<mutex>& __lk,
       chrono::time_point<chrono::system_clock, chrono::nanoseconds>) _NOEXCEPT;
};
中の関数は直感的に実現されています.注意すべきことは:
cv_statusは時間を判断することで確定され、タイムアウトしたらcv_に戻ります.status:timeout、もしタイムアウトがないなら、cv_に戻ります.status::ノ_timeout
conditionvariable:wait_until関数は、1つのpredicateに入ることができます.すなわち、1人のユーザがカスタマイズした判定が条件に合致するかどうかの関数です.これもよくあるテンプレートプログラミングの方法です.
template <class _Clock, class _Duration>
cv_status
condition_variable::wait_until(unique_lock<mutex>& __lk,
                               const chrono::time_point<_Clock, _Duration>& __t)
{
    using namespace chrono;
    wait_for(__lk, __t - _Clock::now());
    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
}

template <class _Clock, class _Duration, class _Predicate>
bool
condition_variable::wait_until(unique_lock<mutex>& __lk,
                   const chrono::time_point<_Clock, _Duration>& __t,
                   _Predicate __pred)
{
    while (!__pred())
    {
        if (wait_until(__lk, __t) == cv_status::timeout)
            return __pred();
    }
    return true;
}
std::condition_variable_any
std::condition_variable_anyのインターフェースとstd:condition_variableと同じで、違いはstd:condition_variableはstdしか使えません:unique_ロックで、std:condition_variable_anyは任意のロックオブジェクトを使用することができます.
次はなぜstdを見ますか?variable_anyは任意のロックオブジェクトを使用することができます.
class _LIBCPP_TYPE_VIS condition_variable_any
{
    condition_variable __cv_;
    shared_ptr<mutex>  __mut_;
public:
    condition_variable_any();

    void notify_one() _NOEXCEPT;
    void notify_all() _NOEXCEPT;

    template <class _Lock>
        void wait(_Lock& __lock);
    template <class _Lock, class _Predicate>
        void wait(_Lock& __lock, _Predicate __pred);

    template <class _Lock, class _Clock, class _Duration>
        cv_status
        wait_until(_Lock& __lock,
                   const chrono::time_point<_Clock, _Duration>& __t);

    template <class _Lock, class _Clock, class _Duration, class _Predicate>
        bool
        wait_until(_Lock& __lock,
                   const chrono::time_point<_Clock, _Duration>& __t,
                   _Predicate __pred);

    template <class _Lock, class _Rep, class _Period>
        cv_status
        wait_for(_Lock& __lock,
                 const chrono::duration<_Rep, _Period>& __d);

    template <class _Lock, class _Rep, class _Period, class _Predicate>
        bool
        wait_for(_Lock& __lock,
                 const chrono::duration<_Rep, _Period>& __d,
                 _Predicate __pred);
};
はstdで見られます.variable_anyでは、shared(u)を使いますptr<mutex> __ムント.mutexを包装しに来ました.ですから、すべて分かりました.
回顧std::unique_ロックは、分解時に自動的にmtexを放出するmutexを包装しています.std::condition_variable_anyの中で、この仕事はshared_を譲ります.ptrがやってきました.
そのため、簡単にstdを得ることができます.variable_any会比std::condition_variableはやや遅い結論になりました.
他のもの:
sched_yield()関数のマンマニュアル:sched_yield()causes the caling thread to relinquish the CPU. The thread is moved to the end of the queue for its       static prorit and a new thread gets to run. 
C+14にstdがあります.ロックとストップ:shared_timed_mutexですが、libc++にはまだ対応ができていませんので、分析はしません.
締め括りをつける
llvm libc++の各種muttex、lock、condition variableは実際にposix内の対応を閉じて実現しました.パッケージの技術と細部については細かく勉強する価値があります.
ソースの実现を见终わったら、どうやって使うかが分かります.
参考:
http://en.cppreference.com/w/cpp
http://libcxx.llvm.org/