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);
    }
    复制代码

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

    三、一种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;
    }
    复制代码

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

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

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

  • 相关阅读:
    Java牛角尖问题之static 静态变量和静态代码块的执行顺序
    蓝桥杯 蚂蚁爬楼梯 递归解最短路程问题
    动态规划系列题目学习
    使用Excel快速生成html表格
    C#使用out输出结果
    C#和sql语句中切割函数SUBSTRING的用法和区别
    C# 对DataTable进行操作
    自动生成表创建sql
    .net core获取根目录并转化字符串
    .net core从配置中读取数据并实例对象
  • 原文地址:https://www.cnblogs.com/cyyljw/p/8006841.html
Copyright © 2011-2022 走看看