zoukankan      html  css  js  c++  java
  • 多线程编程之读写锁

      在《多线程编程之Linux环境下的多线程(二)》一文中提到了Linux环境下的多线程同步机制之一的读写锁。本文再详细写一下读写锁的概念和原理。

    一、什么是读写锁

      读写锁(也叫共享-独占锁)实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。

      如果读写锁当前没有读者,也没有写者,那么写者可以立刻获得读写锁,否则它必须“自旋”在那里,直到没有任何写者或读者。如果读写锁没有写者,那么读者可以立即获得该读写锁,否则读者必须“自旋”在那里,直到写者释放该读写锁。读写锁适合于对数据结构的读次数比写次数多很多的场合

    二、一种Linux环境下的实现方法

      下面利用pthread.h提供的mutex和condition来实现一个读写锁:

    #include <pthread.h>
    
    struct rwlock {
        pthread_mutex_t lock;
        pthread_cond_t read, write;
        unsigned readers, writers, read_waiters, write_waiters;
    };
    
    void reader_lock(struct rwlock *self) {
        pthread_mutex_lock(&self->lock);
        if (self->writers || self->write_waiters) {
            self->read_waiters++;
            do pthread_cond_wait(&self->read, &self->lock);
            while (self->writers || self->write_waiters);
            self->read_waiters--;
        }
        self->readers++;
        pthread_mutex_unlock(&self->lock);
    }
    
    void reader_unlock(struct rwlock *self) {
        pthread_mutex_lock(&self->lock);
        self->readers--;
        if (self->write_waiters)
            pthread_cond_signal(&self->write);
        pthread_mutex_unlock(&self->lock);
    }
    
    void writer_lock(struct rwlock *self) {
        pthread_mutex_lock(&self->lock);
        if (self->readers || self->writers) {
            self->write_waiters++;
            do pthread_cond_wait(&self->write, &self->lock);
            while (self->readers || self->writers);
            self->write_waiters--;
        }
        self->writers = 1;
        pthread_mutex_unlock(&self->lock);
    }
    
    void writer_unlock(struct rwlock *self) {
        pthread_mutex_lock(&self->lock);
        self->writers = 0;
        if (self->write_waiters)
            pthread_cond_signal(&self->write);
        else if (self->read_waiters)
            pthread_cond_broadcast(&self->read);
        pthread_mutex_unlock(&self->lock);
    }
    
    void rwlock_init(struct rwlock *self) {
        self->readers = self->writers = self->read_waiters = self->write_waiters = 0;
        pthread_mutex_init(&self->lock, NULL);
        pthread_cond_init(&self->read, NULL);
        pthread_cond_init(&self->write, NULL);
    }
    View Code

       这种实现方式可以在有写锁存在的情况下不增加读锁数量,而是累加读等待数目。

    三、一种Windows环境下的实现方法

      在Windows环境下实现方式也是差不多的,参考如下实例:

    typedef struct _RWLock    
    {
        int count;
        int state;
        HANDLE hRead;
        HANDLE hWrite;
    } RWLock;  
    typedef enum    /* 枚举读写状态 */
    {
        STATE_EMPTY = 0,
        STATE_READ,
        STATE_WRITE
    };
    RWLock* create_read_write_lock(HANDLE hRead, HANDLE hWrite)
    {
        RWLock* pRwLock = NULL;
        assert(NULL != hRead && NULL != hWrite);
        pRwLock = (RWLock*)malloc(sizeof(RWLock));
      
        pRwLock->hRead = hRead;
        pRwLock->hWrite = hWrite;
        pRwLock->count = 0;
        pRwLock->state = STATE_EMPTY;
        return pRwLock;
    }
    void read_lock(RWLock* pRwLock)
    {
        assert(NULL != pRwLock);
        WaitForSingleObject(pRwLock->hRead, INFINITE);
        pRwLock->count ++;
        if(1 == pRwLock->count){
            WaitForSingleObject(pRwLock->hWrite, INFINITE);
            pRwLock->state = STATE_READ;
        }
        ReleaseMutex(pRwLock->hRead);
    }
    void write_lock(RWLock* pRwLock)
    {
        assert(NULL != pRwLock);
        WaitForSingleObject(pRwLock->hWrite, INFINITE);
        pRwLock->state = STATE_WRITE;
    }
    void read_write_unlock(RWLock* pRwLock)
    {
        assert(NULL != pRwLock);
        if(STATE_READ == pRwLock->state){
            WaitForSingleObject(pRwLock->hRead, INFINITE);
            pRwLock->count --;
            if(0 == pRwLock->count){
                pRwLock->state = STATE_EMPTY;
                ReleaseMutex(pRwLock->hWrite);
            }
            ReleaseMutex(pRwLock->hRead);
        }else{
            pRwLock->state = STATE_EMPTY;
            ReleaseMutex(pRwLock->hWrite);
        }
        return;
    }
    View Code

      Windows环境下的实现方式要更加简单一些,不过这种方式的写操作一旦有读操作获取了锁,就只能等待所有读操作执行完了才行。如果一直都有读操作,那么写操作将会一直等待下去。

    四、读写锁使用的经验总结

    (1)读写锁的优势只有在多读少写、代码段运行时间长这两个条件下才会效率达到最大化;
    (2)任何公共数据的修改都必须在锁里面完成;
    (3)读写锁有自己的应用场所,选择合适的应用环境十分重要;
    (4)编写读写锁很容易出错,需要多加练习;
    (5)读锁和写锁一定要分开使用,否则达不到效果。

  • 相关阅读:
    Codeforces Round #646 (Div. 2) B. Subsequence Hate(前缀和/思维)
    Codeforces Round #646 (Div. 2) A. Odd Selection(思维/分类讨论)
    “科林明伦杯”哈尔滨理工大学第十届程序设计竞赛 A.点对最大值(树的直径/树形DP)
    “科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛)(ABCEFHJ)
    Codeforces Round #645 (Div. 2) C. Celex Update(思维)
    Codeforces Round #645 (Div. 2) D. The Best Vacation(二分+前缀和)
    Codeforces Round #645 (Div. 2) B. Maria Breaks the Self-isolation(贪心)
    Codeforces Round #645 (Div. 2) A. Park Lighting
    ORM之SQLALchemy
    python--10--mysql(2)
  • 原文地址:https://www.cnblogs.com/kuliuheng/p/4065304.html
Copyright © 2011-2022 走看看