簡體   English   中英

簡單的讀寫鎖

[英]Simple Read Write Lock

我發現互聯網上的許多讀寫自旋鎖實現都不必要地復雜。 我在 c++ 中寫了一個簡單的讀寫鎖。

誰能告訴我,如果我遺漏了什么?

int r = 0;
int w = 0;

read_lock(void) 
{
     atomic_inc(r); //increment value atomically
     while( w != 0);    
}

read_unlock(void)
{
   atomic_dec(r); // Decrement value atomically
}
write_lock(void)
{
 while( (r != 0) && 
            ( w != 0))
  atomic_inc(w); //increment value atomically
}

write_unlock(void)
{
    atomic_dec(w); //Decrement value atomically
}

用法如下。

read_lock()
// Critical Section
read_unlock();

write_lock()
// Critical Section
write_unlock();

編輯:

感謝您的回答。 我現在將答案更改為原子等價物

如果線程同時訪問rw ,它們就會發生數據競爭。 如果 C++ 程序存在數據爭用,則程序的行為是未定義的。

C++ 標准不保證int是原子的。 即使我們假設訪問int的系統是原子的,即使在這樣的系統上, operator++也可能不是原子操作。 因此,同時增量可能會“消失”。

此外,在write_lock的循環write_lock ,另一個線程也可以在w遞增之前結束它們的循環,從而允許多個同時寫入 - 我認為這個鎖應該防止這種情況。


最后,這似乎是實現自旋鎖的嘗試。 自旋鎖有優點也有缺點。 它們的缺點是它們在阻塞時消耗了線程的所有 CPU 周期。 這是非常低效的資源使用,不利於電池時間,也不利於其他可以使用這些循環的進程。 但如果等待時間很短,它可能是最佳的。

最簡單的實現是使用單個整數值。 -1 表示當前的寫入狀態,0 表示它沒有被讀取或寫入,正值表示它正在被那么多線程讀取。

使用 atomic_int 和 compare_exchange_weak (或強但弱就足夠了)

std::atomic_int l=0;

void write_lock() {
    int v = 0;
    while( !l.compare_exchange_weak( v, -1 ) ) 
       v = 0; // it will set it to what it currently held
}

void write_unlock() {
    l = 0; // no need to compare_exchange
}

void read_lock() {
    int v = l.load();
    while( v < 0 || !l.compare_exchange_weak(v, v+1) )
       v = l.load();
}

void read_unlock() {
    --l; // no need to do anything else
}

我認為這應該可以工作,並且有 RAII 對象,即創建一個自動 object 鎖定每種類型的構造並在破壞時解鎖。

可以這樣做:

class AtomicWriteSpinScopedLock
{
   private:
      atomic_int& l_;

   public:
      // handle copy/assign/move issues

      explicit AtomicWriteSpinScopedLock( atomic_int& l ) :
         l_(l)
       {
           int v = 0;   
           while( !l.compare_exchange_weak( v, -1 ) ) 
             v = 0; // it will set it to what it currently held
      }

      ~AtomicWriteSpinScopedLock()
       {
           l_ = 0;
       }
 };
       
class AtomicReadSpinScopedLock
{
   private:
      atomic_int& l_;

   public:
      // handle copy/assign/move issues

      explicit AtomicReadSpinScopedLock( atomic_int& l ) :
         l_(l)
       {
          int v = l.load();
          while( v < 0 || !l.compare_exchange_weak(v, v+1) )
               v = l.load();          }
       }

      ~AtomicReadSpinScopedLock()
       {
           --l_;
       }
 };

在鎖定寫入值必須為 0 並且您必須將其交換為 -1,因此請繼續嘗試這樣做。

鎖定時讀取的值必須是非負數,然后您嘗試增加它,因此可能會對其他讀取器進行重試,而不是獲取鎖,而是設置其計數。

compare_exchange_weak 將第一個參數設置為交換失敗時實際持有的參數,第二個參數是您嘗試將其更改為的參數。 如果交換則返回 true,否則返回 false。

效率如何? 這是一個自旋鎖。 它會在等待時使用 CPU 周期,因此最好盡快可用:更新或讀取數據應為 swift。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM