2011-12-26 94 views
4

我试图只使用互斥锁来实现读/写锁(仅用于学习)。正当我想我已经覆盖了所有的角落案例(因为程序使用了各种组合),我已经意识到,我忽略了这个事实(因为它在Ubuntu的工作),该互斥体应该由线程的所有者释放。下面是我的实施,仅使用互斥锁的读/写锁实现?

class rw_lock_t{ 

    int NoOfReaders; 
    int NoOfWriters, NoOfWritersWaiting; 
    pthread_mutex_t class_mutex; 
    pthread_cond_t class_cond; 
    pthread_mutex_t data_mutex; 

public: 

    rw_lock_t() 
    : NoOfReaders(0), 
     NoOfWriters(0), NoOfWritersWaiting(0) 
    { 
      pthread_mutex_init(&class_mutex, NULL); 
      pthread_mutex_init(&data_mutex, NULL); 
      pthread_cond_init(&class_cond, NULL); 
    } 
    void r_lock() 
    { 
      pthread_mutex_lock(&class_mutex); 
      //while(NoOfWriters!=0 || NoOfWritersWaiting!=0) //Writer Preference 
      while(NoOfWriters!=0) 
      { 
        pthread_cond_wait(&class_cond, &class_mutex); 
      } 
      if(NoOfReaders==0) 
      { 
        pthread_mutex_unlock(&class_mutex); 
        pthread_mutex_lock(&data_mutex); 
        pthread_mutex_lock(&class_mutex); 
        NoOfReaders++; 
        pthread_mutex_unlock(&class_mutex); 
      } 
      else if(NoOfReaders>0) //Already Locked 
      { 
        NoOfReaders++; 
        pthread_mutex_unlock(&class_mutex); 
      } 
    } 
    void w_lock() 
    { 
      pthread_mutex_lock(&class_mutex); 
      NoOfWritersWaiting++; 
      while(NoOfReaders!=0 && NoOfWriters!=0) 
      { 
        pthread_cond_wait(&class_cond, &class_mutex); 
      } 
      pthread_mutex_unlock(&class_mutex); 

      pthread_mutex_lock(&data_mutex); 
      pthread_mutex_lock(&class_mutex); 
      NoOfWritersWaiting--; NoOfWriters++; 
      pthread_mutex_unlock(&class_mutex); 
    } 
    void r_unlock() 
    { 
      pthread_mutex_lock(&class_mutex); 
      NoOfReaders--; 
      if(NoOfReaders==0) 
        pthread_mutex_unlock(&data_mutex); 
      pthread_mutex_unlock(&class_mutex); 
      pthread_cond_signal(&class_cond); 
    } 
    void w_unlock() 
    { 
      pthread_mutex_lock(&class_mutex); 
      NoOfWriters--; 
      if(NoOfWriters==0) 
        pthread_mutex_unlock(&data_mutex); 
      pthread_mutex_unlock(&class_mutex); 
      pthread_cond_signal(&class_cond); 
    } 
}; 

我现在的问题是,什么是最好的方式(微小的变化)纠正。信号量绝对是空闲的选择,但我认为解决方案如下

解决方案#1

1)我将有一个专门的线程,只锁定/解锁读情况互斥。

2)此线程将等待条件变量从r_lock或r_unlock获取信号。

3)r_lock和r_unlock将代替执行“pthread_mutex_lock/unlock(& data_mutex);”,而是指示专用线程锁定。

4)我要记住许多事实对于此实现,

  • 的信令和实际锁定是两个不同的事件,因此可能需要同步。

  • 将需要一个互斥+ condVariable +线程和更多的同步额外。

更新:解决方案2

1)谁做实际的锁定将保持其全球范围的TID线程。 2)每当线程解锁将确保与全局tid检查相等。 3)如果匹配将等待“NoOfReaders == 0”条件并解锁它。

那么,有没有更好的方法可以纠正程序。

回答

8

你不需要一个单独的互斥“数据”;如果其内部逻辑是正确的,则整个构造将用作数据锁定。相反,您可以为读者和作者使用两个单独的条件变量,以便您可以在不影响等待作者的情况下广播所有等待的读者。代码如下;你也可以看到这样更简单。此外,我添加了一个析构函数并修复了w_lock中的一个错误:等待的条件应该是(NoOfReaders!=0 || NoOfWriters!=0),而不是&&

class rw_lock_t { 

    int NoOfReaders; 
    int NoOfWriters, NoOfWritersWaiting; 
    pthread_mutex_t class_mutex; 
    pthread_cond_t reader_gate; 
    pthread_cond_t writer_gate; 

public: 

    rw_lock_t() 
    : NoOfReaders(0), NoOfWriters(0), NoOfWritersWating(0), 
     class_mutex(PTHREAD_MUTEX_INITIALIZER), 
     reader_gate(PTHREAD_COND_INITIALIZER), 
     writer_gate(PTHREAD_COND_INITIALIZER) 
    {} 
    ~rw_lock_t() 
    { 
     pthread_mutex_destroy(&class_mutex); 
     pthread_cond_destroy(&reader_gate); 
     pthread_cond_destroy(&writer_gate); 
    } 
    void r_lock() 
    { 
     pthread_mutex_lock(&class_mutex); 
     //while(NoOfWriters>0 || NoOfWritersWaiting>0) //Writer Preference 
     while(NoOfWriters>0) 
     { 
      pthread_cond_wait(&reader_gate, &class_mutex); 
     } 
     NoOfReaders++;   
     pthread_mutex_unlock(&class_mutex); 
    } 
    void w_lock() 
    { 
     pthread_mutex_lock(&class_mutex); 
     NoOfWritersWaiting++; 
     while(NoOfReaders>0 || NoOfWriters>0) 
     { 
      pthread_cond_wait(&writer_gate, &class_mutex); 
     } 
     NoOfWritersWaiting--; NoOfWriters++; 
     pthread_mutex_unlock(&class_mutex); 
    } 
    void r_unlock() 
    { 
     pthread_mutex_lock(&class_mutex); 
     NoOfReaders--; 
     if(NoOfReaders==0 && NoOfWritersWaiting>0) 
      pthread_cond_signal(&writer_gate); 
     pthread_mutex_unlock(&class_mutex); 
    } 
    void w_unlock() 
    { 
     pthread_mutex_lock(&class_mutex); 
     NoOfWriters--; 
     if(NoOfWritersWaiting>0) 
      pthread_cond_signal(&writer_gate); 
     //else //Writer Preference - don't signal readers unless no writers 
     pthread_cond_broadcast(&reader_gate); 
     pthread_mutex_unlock(&class_mutex); 
    } 
}; 
+2

使用条件,它不只是互斥。 – Alexandru 2013-01-10 21:55:25

+0

这是一个非常好的答案。没有家庭作业请! – Kobor42 2013-11-19 12:11:31

+0

我们不应该检查r_lock()和w_lock()函数中的虚假唤醒条件吗?这是来自manpage:“当使用条件变量时,总是有一个布尔谓词涉及到与每个条件相关的共享变量,如果线程应该继续执行,则等待为真,可能会发生从pthread_cond_timedwait()或pthread_cond_wait()函数的虚假唤醒。 pthread_cond_timedwait()或pthread_cond_wait()的返回并不意味着这个谓词的值有任何意义,应该在返回时重新评估谓词。“ --->如果返回false,则返回循环! – cforfun 2016-02-16 02:29:39

0
class ReadWriteLock { 
    mutex writeLock; 
    mutex readLock; 
    int readCount; 
public: 
    ReadWriteLock() { 
     readCount = 0; 
    } 
    void LockWrite() { 
     writeLock.lock(); 
    } 
    void UnlockWrite() { 
     writeLock.unlock(); 
    } 
    void LockRead() { 
     lock_guard<mutex> lock(readLock); 
     ++readCount; 
     if (1 == readCount) { 
      LockWrite(); 
     } 
    } 
    void UnlockRead() { 
     lock_guard<mutex> lock(readLock); 
     --readCount; 
     if (0 == readCount) { 
      UnlockWrite(); 
     } 
    } 
}; 

正如阿列克谢指出,如果最后一次读线程UnlockWrite不是第一次读线程LockWrite,该行为是不确定的。请参阅 std :: mutex :: unlock http://www.cplusplus.com/reference/mutex/mutex/unlock/ Windows ReleaseMutex:http://msdn.microsoft.com/en-us/library/windows/desktop/ms685066(v=vs.85).aspx

+0

存在一个问题,即最后一个读取器线程解锁了写入器互斥锁,它可能与第一个锁定写入器互斥锁的读取器线程不同。对于'std :: mutex',它不被允许 - 调用unlock()的线程应该拥有这个互斥量。 – 2014-09-17 12:38:04

+0

Alexey,你说得对。所以我可以得到的解决方案就像您的cv一样。 – QAMichaelPeng 2014-09-24 15:50:36

+0

互斥锁解锁: pthread_mutex_unlock:http://www.lehman.cuny.edu/cgi-bin/man-cgi?pthread_mutex_lock+3 – QAMichaelPeng 2014-09-24 16:03:54