zoukankan      html  css  js  c++  java
  • 读写锁机制

      在以前的一篇博文Linux多线程编程初探中,只提到了用于线程同步的互斥锁、条件变量,而没有提及读写锁(read-write lock)。

      本文主要整理自以下文章:

      读写锁(read-write lock)机制-----多线程同步问题的解决

      请用普通的互斥锁编程实现一个读写锁

    读写锁

      读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁。

      1)当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞.

      2)当读写锁在读加锁状态时, 所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行枷锁的线程将阻塞;

      3)当读写锁在读模式锁状态时, 如果有另外线程试图以写模式加锁读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁长期占用, 而等待的写模式锁请求长期阻塞;

      这种锁适用对数据结构进行读的次数比写的次数多的情况

    读写锁API

    初始化和销毁

      对于读写锁变量的初始化可以有两种方式,一种是通过给一个静态分配的读写锁赋予常值PTHREAD_RWLOCK_INITIALIZER来初始化它,另一种方法就是通过调用pthread_rwlock_init()来动态的初始化。而当某个线程不再需要读写锁的时候,可以通过调用pthread_rwlock_destroy来销毁该锁。函数原型如下:

    #include <pthread.h>
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    // 成功则返回0, 出错则返回错误编号.

      在释放某个读写锁占用的内存之前,要先通过pthread_rwlock_destroy对读写锁进行清理,释放由pthread_rwlock_init所分配的资源。在初始化某个读写锁的时候,如果属性指针attr是个空指针的话,表示默认的属性;如果想要使用非默认属性,则要使用到下面的两个函数:

    #include 
    int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
    int pthread_rwlockattr_destroy(pthread_rwlockatttr_t *attr);
    // 成功返回0,出错则返回错误码。

      这里还需要说明的是,当初始化读写锁完毕以后呢,该锁就处于一个非锁定状态。数据类型为pthread_rwlockattr_t的某个属性对象一旦初始化了,就可以通过不同的函数调用来启用或者是禁用某个特定的属性。

    读加锁和写加锁

      读写锁的数据类型是pthread_rwlock_t,如果这个数据类型中的某个变量是静态分配的,那么可以通过给它赋予常值PTHREAD_RWLOCK_INITIALIZAR来初始化它。pthread_rwlock_rdlock()用来获取读出锁,如果相应的读出锁已经被某个写入者占有,那么就阻塞调用线程。pthread_rwlock_wrlock()用来获取一个写入锁,如果相应的写入锁已经被其它写入者或者一个或多个读出者占有,那么就阻塞该调用线程;pthread_rwlock_unlock()用来释放一个读出或者写入锁。函数原型如下:

    #include <pthread.h>
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
    // 成功则返回0, 出错则返回错误编号.

      要注意的是其中获取锁的两个函数的操作都是阻塞操作,也就是说获取不到锁的话,那么调用线程不是立即返回,而是阻塞执行。有写情况下,这种阻塞式的获取所得方式可能不是很适用,所以,接下来引入两个采用非阻塞方式获取读写锁的函数pthread_rwlock_tryrdlock()和pthread_rwlock_trywrlock(),非阻塞方式下获取锁的时候,如果不能马上获取到,就会立即返回一个EBUSY错误,而不是把调用线程投入到睡眠等待。函数原型如下:

    #include <pthread.h>
    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    // 成功则返回0, 出错则返回错误编号.

    用互斥锁实现读写锁

      伪代码如下:

     1 count_mutex = mutex_init();
     2 write_mutex = mutex_init();
     3 read_count = 0;
     4 
     5 void read_lock{
     6     lock(count_mutex);
     7     read_count++;
     8     if (read_count == 1) {
     9         lock(write_mutex);
    10     }
    11     unlock(count_mutex);
    12 }
    13 
    14 void read_unlock{
    15     lock(count_mutex);
    16     read_count--;
    17     if (read_count == 0) {
    18         unlock(write_mutex);
    19     }
    20     unlock(count_mutex);
    21 }
    22 
    23 void write_lock{
    24     lock(write_mutex);
    25 }
    26 
    27 void write_unlock{
    28     unlock(write_mutex);
    29 }

      

  • 相关阅读:
    ElasticSearch 清理索引
    Docker 服务接入SkyWalking
    Promethues mysql_exporter 集中式监控
    修改SVN密码自助平台
    快速排序(golang)
    ElasticSearch Xpack集群认证和elasticsearch-head配置
    Ansible一个tasks失败则终止剩余的task
    Consul安装
    最纯净的开发者技术交流社群
    Flutter中的报错:(IOS pod 版本错误) error: compiling for iOS 8.0, but module 'xxx' has a minimum deployment target of iOS 9.0
  • 原文地址:https://www.cnblogs.com/xiehongfeng100/p/4782135.html
Copyright © 2011-2022 走看看