简单的读写锁



我发现通过Internet上的许多读写旋转锁实现非常复杂。我在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 程序具有数据率,则该程序的行为是未定义的。

int不能由C 标准保证为原子。即使我们假设访问int的系统是原子,即使在此类系统上,operator++也可能不是原子操作。因此,同时增量可能会"消失"。

此外,在write_lock中的循环之后,另一个线程也可以在w递增之前结束循环,从而允许多个同时的作家 - 我认为此锁应该可以预防。

>

最后,这似乎是实现自旋锁的尝试。Spinlock具有优势和缺点。他们的缺点是,他们在阻塞时消耗了所有线程的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对象,即创建一个自动对象,可以锁定构造并解锁每种类型的破坏。

可以这样做的:

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,如果没有交换,则返回。

有多高效?这是一个旋转锁。它将在等待时使用CPU周期,因此最好很快可以使用:更新或读取数据应迅速进行。

相关内容

  • 没有找到相关文章

最新更新