原文: http://blog.chinaunix.net/uid-27177626-id-3791049.html

----------------------------------------------------------------------

读写锁(read-write lock)

一 综述
    在一些程序中存在读者写者问题,也就是说,对某些资源的访问会  存在两种可能的情况,一种是访问必须是排它行的,就是独占的意思,这称作写操作;另一种情况就是访问方式可以是共享的,就是说可以有多个线程同时去访问某个资源,这种就称作读操作。这个问题模型是从对文件的读写操作中引申出来的。
    读写锁比起mutex具有更高的适用性,具有更高的并行性,可以有多个线程同时占用读模式的读写锁,但是只能有一个线程占用写模式的读写锁,读写锁的三种状态:
1.当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞
2.当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行加锁的线程将会被阻塞
3.当读写锁在读模式的锁状态时,如果有另外的线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁的请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求则长期阻塞。
    读写锁最适用于对数据结构的读操作次数多于写操作的场合,因为,读模式锁定时可以共享,而写模式锁定时只能某个线程独占资源,因而,读写锁也可以叫做个共享-独占锁。
    处理读者-写者问题的两种常见策略是强读者同步(strong reader synchronization)和强写者同步(strong writer synchronization).    在强读者同步中,总是给读者更高的优先权,只要写者当前没有进行写操作,读者就可以获得访问权限;而在强写者同步中,则往往将优先权交付给写者,而读者只能等到所有正在等待的或者是正在执行的写者结束以后才能执行。关于读者-写者模型中,由于读者往往会要求查看最新的信息记录,所以航班订票系统往往会使用强写者同步策略,而图书馆查阅系统则采用强读者同步策略。
    读写锁机制是由posix提供的,如果写者没有持有读写锁,那么所有的读者多可以持有这把锁,而一旦有某个写者阻塞在上锁的时候,那么就由posix系统来决定是否允许读者获取该锁。
二 读写锁相关的API
1.初始化和销毁读写锁
    对于读写锁变量的初始化可以有两种方式,一种是通过给一个静态分配的读写锁赋予常值PTHREAD_RWLOCK_INITIALIZER来初始化它,另一种方法就是通过调用pthread_rwlock_init()来动态的初始化。而当某个线程不再需要读写锁的时候,可以通过调用pthread_rwlock_destroy来销毁该锁。函数原型如下:
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwptr, const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwptr);
这两个函数如果执行成功均返回0,如果出错则返回错误码。
在释放某个读写锁占用的内存之前,要先通过pthread_rwlock_destroy对读写锁进行清理,释放由pthread_rwlock_init所分配的资源。
在初始化某个读写锁的时候,如果属性指针attr是个空指针的话,表示默认的属性;如果想要使用非默认属性,则要使用到下面的两个函数:
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockatttr_t *attr);
这两个函数同样的,如果执行成功返回0,失败返回错误码。
这里还需要说明的是,当初始化读写锁完毕以后呢,该锁就处于一个非锁定状态。
数据类型为pthread_rwlockattr_t的某个属性对象一旦初始化了,就可以通过不同的函数调用来启用或者是禁用某个特定的属性。
2.获取和释放读写锁
读写锁的数据类型是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 *rwptr);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwptr);
int pthread_rwlock_unlock(pthread_rwlock_t *rwptr);
这三个函数若调用成功则返回0,失败就返回错误码。要注意的是其中获取锁的两个函数的操作都是阻塞操作,也就是说获取不到锁的话,那么调用线程不是立即返回,而是阻塞执行。有写情况下,这种阻塞式的获取所得方式可能不是很适用,所以,接下来引入两个采用非阻塞方式获取读写锁的函数pthread_rwlock_tryrdlock()和pthread_rwlock_trywrlock(),非阻塞方式下获取锁的时候,如果不能马上获取到,就会立即返回一个EBUSY错误,而不是把调用线程投入到睡眠等待。函数原型如下:
#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwptr);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwptr);
同样地,这两个函数调用成功返回0,失败返回错误码。
三 实例
读者-写者模型来实现多线程同步问题(原文http://hi.baidu.com/tekuba/item/d67e82ce52444522e90f2ee8)
https://github.com/helianthuslulu/LINUX_IPC

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

  1. 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁

    1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...

  2. 从自旋锁、睡眠锁、读写锁到 Linux RCU 机制讲解

    ​    同步自我的 csdn 博客 6.S081 从自旋锁.睡眠锁.读写锁到 Linux RCU 机制讲解_我说我谁呢 --CSDN博客 总结一下 O/S 课程里面和锁相关的内容. 本文是 6.S0 ...

  3. Linux程序设计学习笔记----多线程编程线程同步机制之相互排斥量(锁)与读写锁

    相互排斥锁通信机制 基本原理 相互排斥锁以排他方式防止共享数据被并发訪问,相互排斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个相互排斥锁逻辑上绑定之后,对该资源的訪问操作例如以下: ...

  4. java读写锁实现数据同步访问

    锁机制最大的改进之一就是ReadWriteLock接口和它的唯一实现类ReentrantReadWriteLock.这个类有两个锁,一个是读操作锁,另一个是写操作锁.使用读操作锁时可以允许多个线程同时 ...

  5. java多线程:并发包中ReentrantReadWriteLock读写锁的锁降级模板

    写锁降级为读锁,但读锁不可升级或降级为写锁. 锁降级是为了让当前线程感知到数据的变化. //读写锁 private ReentrantReadWriteLock lock=new ReentrantR ...

  6. Java 多线程同步的五种方法

    一.引言 闲话不多说,进入正题. 二.为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常.举个例子 ...

  7. Java 并发包中的读写锁及其实现分析

    1. 前言 在Java并发包中常用的锁(如:ReentrantLock),基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时 刻可以允许多个读线程访问,但是在写线程访问时,所有 ...

  8. 浅谈Java中的锁:Synchronized、重入锁、读写锁

    Java开发必须要掌握的知识点就包括如何使用锁在多线程的环境下控制对资源的访问限制 ◆ Synchronized ◆ 首先我们来看一段简单的代码: 12345678910111213141516171 ...

  9. java多线程同步(转)

    原文地址:http://developer.51cto.com/art/201509/490965.htm 一.场景 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时, ...

随机推荐

  1. Sql批量插入方法

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  2. Python随笔-快排

    def swap(arr, i, j): temp = arr[i] arr[i] = arr[j] arr[j] = temp def part(arr, beg, end): : return b ...

  3. Python--10、线程

    线程 每个进程里都有一个控制线程,进程不是一个执行单位,线程是执行单位,进程是资源单位(资源隔离).进程下可以开多个线程,多线程共享进程内的资源.创建线程的速度比创建进程的速度快,因为创建线程不需要再 ...

  4. MFC SkinMagic使用方法

    皮肤库下载地址 https://pan.baidu.com/s/1IuiYlFUJIi-TS9Cgz3M6RA 1.创建MFC工程 2.然后把corona.smf.SkinMagic.dll.Skin ...

  5. JS——scroll动画

    固定导航栏 1.计算导航栏到顶部的距离值 2.当scrollTop值大于这个距离值就添加定位,当小于距离值后解除定位 注意事项:当导航栏添加定位之后,导航栏就脱离了文档流,也就是不占位了,下面的盒子就 ...

  6. CSS——样式隐藏

    overflow:hidden:  溢出隐藏 visibility:hidden:   隐藏元素    隐藏之后还占据原来的位置. display:none:      隐藏元素    隐藏之后不占据 ...

  7. dom4j.jar 的调试方法

    1.将jar包的路径写在 classpath下 在cmd窗口中,查看 classpath的内容是否已经加上该路径,win7 下cmd窗口一定要是管理员身份执行 2.在D盘新建一个DOM4JWriter ...

  8. Find the build UUID in a Crash Report

    1) Find the build UUID in a Crash Report The first line in the "Binary Images:" section of ...

  9. Appium使用方法说明

    global driver# 元素定位driver.find_element_by_id("id") # id定位driver.find_element_by_name(" ...

  10. Django - orm字段类型介绍

    1.根据类自动创建数据库表 #app.py下的models.py python manage.py makemigrations python manage.py migrate 执行完上述命令后,自 ...