仅使用互斥锁读/写锁实现?

时间:2011-12-26 12:53:36

标签: c++ multithreading pthreads mutex

我试图仅使用互斥锁实现读/写锁定(仅用于学习)。就在我认为我已经覆盖所有角落的情况下(因为程序使用各种组合),我已经意识到,我忽略了事实(因为它在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)我必须记住这个实现的许多事实,

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

  • 需要一个mutex + condVariable +线程以及更多的同步额外。

更新:解决方案#2

1)执行实际锁定的线程将全局保持其tid。

2)每当线程解锁时,都会确保检查与全局tid相等。

3)如果匹配将等待“NoOfReaders == 0”条件并解锁。

那么,是否有更好的方法可以纠正该计划。

2 个答案:

答案 0 :(得分:9)

您不需要单独的互斥锁“用于数据”;如果内部逻辑正确,则整个构造将用作数据锁。相反,您可以为读者和作者使用两个单独的条件变量,这样您就可以广播所有等待的读者而不会影响等待的编写者。代码如下;你也可以看到这种方式更简单。此外,我添加了一个析构函数并修复了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);
    }
};

答案 1 :(得分: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();
        }
    }
};

正如Alexey指出的那样,如果最后一次读取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