2016-12-16 6 views
7

boost::shared_mutexまたはstd::shared_mutex(C++ 17)は、シングルライター、複数リーダーアクセスに使用できます。教育上の練習として、私はスピンロックを使用し、他の制限がある(例えば公平性ポリシー)単純な実装を組み立てましたが、実際のアプリケーションでは使用されないことは明らかです。C++ shared_mutexの実装

スレッドがロックを保持していない場合、ミューテックスは参照カウントをゼロに保つという考えがあります。 > 0の場合、値はアクセス権を持つ読者の数を表します。 -1の場合、1つのライターがアクセス権を持ちます。

これは、データレースのない正しい実装(特に、使用されている最小限のメモリ順序)ですか?

#include <atomic> 

class my_shared_mutex { 
    std::atomic<int> refcount{0}; 
public: 

    void lock() // write lock 
    { 
     int val; 
     do { 
      val = 0; // Can only take a write lock when refcount == 0 

     } while (!refcount.compare_exchange_weak(val, -1, std::memory_order_acquire)); 
     // can memory_order_relaxed be used if only a single thread takes write locks ? 
    } 

    void unlock() // write unlock 
    { 
     refcount.store(0, std::memory_order_release); 
    } 

    void lock_shared() // read lock 
    { 
     int val; 
     do { 
      do { 
       val = refcount.load(std::memory_order_relaxed); 

      } while (val == -1); // spinning until the write lock is released 

     } while (!refcount.compare_exchange_weak(val, val+1, std::memory_order_acquire)); 
    } 

    void unlock_shared() // read unlock 
    { 
     refcount.fetch_sub(1, std::memory_order_relaxed); 
    } 
}; 

答えて

3

(私はC++ compare_exchange_weak機能、ないcmpxchg instructionの省略形としてCMPXCHG使用しています)。

lock_shared間違いなく、読み取り時にスピンし、cmpxchgでスピンするよりパフォーマンスがはるかに優れている場合は、cmpxchgを試みるだけです。私はあなたが正しいものであることを強制されたと思いますが、-1を0に変更して書き込みロックを解除することは避けてください。

それは読者クリティカルセクションからの荷重が発生する前に必ず作家が書いて起動しないにするために、共有データ構造から負荷を注文する必要があるので、私は、unlock_sharedmo_relaxedmo_releaseを使用していないされるべきだと思います。 (LoadStore reorderingは、x86がStoreLoadの並べ替えだけを行うにもかかわらず、弱く順序付けられたアーキテクチャ上のものです。)A Release operation will order preceding loads and keep them inside the critical section。 (書き込みlock中)


:単一スレッドのみが書き込みロックを取る場合、//を使用することmemory_order_relaxedことができますか?

いいえ、unlock_sharedから-店をリリースあなたはまだクリティカルセクション内の書き込みを維持する必要があり、そうCMPXCHGはまだ(C++の用語で)と同期する必要があります。

+0

私はunlock_sharedのメモリの順序についてはわかりませんでしたが、私の推論は、読み取り専用のアクセスしか持たず、保護するデータを変更できないため、実際には何もリリースしていないということでした。 – LWimsey

+0

@LWimsey:店舗の注文よりも荷物の発注について考えることができますが、それは本当のことです。 L1キャッシュからデータを読み込んだ時点で、負荷は全体的に可視になります。 (これは、グローバルコヒーレントキャッシュから単一のCPUのアウトオブオーダーコアへのコピーを作成するためです。) –