Linux线程同步之读写锁(rwlock)
读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步,
和互斥量不同的是:互斥量会把试图进入已保护的临界区的线程都阻塞;然而读写锁会视当前进入临界区的线程和请求进入临界区的线程的属性来判断是否允许线程进入。
相对互斥量只有加锁和不加锁两种状态,读写锁有三种状态:读模式下的加锁,写模式下的加锁,不加锁。
读写锁的使用规则:
- 只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁;
- 只有读写锁处于不加锁状态时,才能进行写模式下的加锁;
读写锁也称为共享-独占(shared-exclusive)锁,当读写锁以读模式加锁时,它是以共享模式锁住,当以写模式加锁时,它是以独占模式锁住。读写锁非常适合读数据的频率远大于写数据的频率从的应用中。这样可以在任何时刻运行多个读线程并发的执行,给程序带来了更高的并发度。
需要提到的是:读写锁到目前为止仍然不是属于POSIX标准,本文讨论的读写锁函数都是有Open Group定义的的。例如下面是在我机器上,编译器是gcc version 4.4.6,关于读写锁的定义是包含在预处理命令中的:
- #if defined __USE_UNIX98 || defined __USE_XOPEN2K
- ... 读写锁相关函数声明...
- #endif
1读写锁的初始化和销毁
- /* Initialize read-write lock */
- int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
- __const pthread_rwlockattr_t *__restrict __attr);
- /* Destroy read-write lock */
- extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
- 返回值:成功返回0,否则返回错误代码
上面两个函数分别由于读写锁的初始化和销毁。和互斥量,条件变量一样,如果读写锁是静态分配的,可以通过常量进行初始化,如下:
- pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
也可以通过pthread_rwlock_init()进行初始化。对于动态分配的读写锁由于不能直接赋值进行初始化,只能通过这种方式进行初始化。pthread_rwlock_init()第二个参数是读写锁的属性,如果采用默认属性,可以传入空指针NULL。
那么当不在需要使用时及释放(自动或者手动)读写锁占用的内存之前,需要调用pthread_rwlock_destroy()进行销毁读写锁占用的资源。
2读写锁的属性设置
- /* 初始化读写锁属性对象 */
- int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr);
- /* 销毁读写锁属性对象 */
- int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);
- /* 获取读写锁属性对象在进程间共享与否的标识*/
- int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * __restrict __attr,
- int *__restrict __pshared);
- /* 设置读写锁属性对象,标识在进程间共享与否 */
- int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, int __pshared);
- 返回值:成功返回0,否则返回错误代码
这个属性设置和互斥量的基本一样,具体可以参考互斥量的设置互斥量的属性设置
3读写锁的使用
- /* 读模式下加锁 */
- int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
- /* 非阻塞的读模式下加锁 */
- int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
- # ifdef __USE_XOPEN2K
- /* 限时等待的读模式加锁 */
- int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
- __const struct timespec *__restrict __abstime);
- # endif
- /* 写模式下加锁 */
- int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
- /* 非阻塞的写模式下加锁 */
- int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
- # ifdef __USE_XOPEN2K
- /* 限时等待的写模式加锁 */
- int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
- __const struct timespec *__restrict __abstime);
- # endif
- /* 解锁 */
- int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
- 返回值:成功返回0,否则返回错误代码
(1)pthread_rwlock_rdlock()系列函数
pthread_rwlock_rdlock()用于以读模式即共享模式获取读写锁,如果读写锁已经被某个线程以写模式占用,那么调用线程就被阻塞。在实现读写锁的时候可以对共享模式下锁的数量进行限制(目前不知如何限制)。
pthread_rwlock_tryrdlock()和pthread_rwlock_rdlock()的唯一区别就是,在无法获取读写锁的时候,调用线程不会阻塞,会立即返回,并返回错误代码EBUSY。
pthread_rwlock_timedrdlock()是限时等待读模式加锁,时间参数struct timespec * __restrict __abstime也是绝对时间,和条件变量的pthread_cond_timedwait()使用基本一致,具体可以参考pthread_cond_timedwait()3条件变量的使用
(2)pthread_rwlock_wrlock()系列函数
pthread_rwlock_wrlock()用于写模式即独占模式获取读写锁,如果读写锁已经被其他线程占用,不论是以共享模式还是独占模式占用,调用线程都会进入阻塞状态。
pthread_rwlock_trywrlock()在无法获取读写锁的时候,调用线程不会进入睡眠,会立即返回,并返回错误代码EBUSY。
pthread_rwlock_timedwrlock()是限时等待写模式加锁,也和条件变量的pthread_cond_timedwait()使用基本一致,具体可以参考pthread_cond_timedwait()3条件变量的使用。
(3)pthread_rwlock_unlock()
无论以共享模式还是独占模式获得的读写锁,都可以通过调用pthread_rwlock_unlock()函数进行释放该读写锁。
下面是测试代码:
- #include <iostream>
- #include <cstdlib>
- #include <unistd.h>
- #include <pthread.h>
- using namespace std;
- struct{
- pthread_rwlock_t rwlock;
- int product;
- }sharedData = {PTHREAD_RWLOCK_INITIALIZER, 0};
- void * produce(void *ptr)
- {
- for (int i = 0; i < 5; ++i)
- {
- pthread_rwlock_wrlock(&sharedData.rwlock);
- sharedData.product = i;
- pthread_rwlock_unlock(&sharedData.rwlock);
- sleep(1);
- }
- }
- void * consume1(void *ptr)
- {
- for (int i = 0; i < 5;)
- {
- pthread_rwlock_rdlock(&sharedData.rwlock);
- cout<<"consume1:"<<sharedData.product<<endl;
- pthread_rwlock_unlock(&sharedData.rwlock);
- ++i;
- sleep(1);
- }
- }
- void * consume2(void *ptr)
- {
- for (int i = 0; i < 5;)
- {
- pthread_rwlock_rdlock(&sharedData.rwlock);
- cout<<"consume2:"<<sharedData.product<<endl;
- pthread_rwlock_unlock(&sharedData.rwlock);
- ++i;
- sleep(1);
- }
- }
- int main()
- {
- pthread_t tid1, tid2, tid3;
- pthread_create(&tid1, NULL, produce, NULL);
- pthread_create(&tid2, NULL, consume1, NULL);
- pthread_create(&tid3, NULL, consume2, NULL);
- void *retVal;
- pthread_join(tid1, &retVal);
- pthread_join(tid2, &retVal);
- pthread_join(tid3, &retVal);
- return 0;
- }
测试结果如下:
- consume1:0
- consume2:0
- consume2:0
- consume1:1
- consume2:1
- consume1:2
- consume2:2
- consume1:3
- consume2:3
- consume1:4
如果把consume1的解锁注释掉,如下:
- void * consume1(void *ptr)
- {
- for (int i = 0; i < 5;)
- {
- pthread_rwlock_rdlock(&sharedData.rwlock);
- cout<<"consume1:"<<sharedData.product<<endl;
- //pthread_rwlock_unlock(&sharedData.rwlock);
- ++i;
- sleep(1);
- }
- }
程序的执行结果如下:
- consume1:0
- consume2:0
- consume2:0
- consume1:0
- consume2:0
- consume1:0
- consume2:0
- consume1:0
- consume2:0
- consume1:0
从执行结果可以看出Linux 2.6.18提供的读写锁函数是优先考虑等待读模式占用锁的线程,这种实现的一个很大缺陷就是出现写入线程饿死的情况。
Jun 26, 2013 AM 00:08 @Library
原文:http://blog.csdn.net/anonymalias/article/details/9174595
Linux线程同步之读写锁(rwlock)的更多相关文章
- linux线程同步(3)-读写锁
一.概述 读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...
- UNIX环境高级编程——线程同步之读写锁以及属性
读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 互 ...
- 线程同步——用户模式下线程同步——Slim读写锁实现线程同步
//Slim读/写锁实现线程同步 SRWlock 的目的和关键段相同:对同一资源进行保护,不让其它线程访问. 但是,与关键段不同的是,SRWlock允许我们区分哪些想要读取资源的线程(读取者线程) 和 ...
- Linux系统编程 —读写锁rwlock
读写锁是另一种实现线程间同步的方式.与互斥量类似,但读写锁将操作分为读.写两种方式,可以多个线程同时占用读模式的读写锁,这样使得读写锁具有更高的并行性. 读写锁的特性为:写独占,读共享:写锁优先级高. ...
- linux c编程:读写锁
什么是读写锁读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的 为什么需要读写锁有时候,在多线程中,有一些公共数据修改的 ...
- 嵌入式 Linux线程同步读写锁rwlock示例
读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁.1. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞:2. ...
- linux线程间同步(1)读写锁
读写锁比mutex有更高的适用性,能够多个线程同一时候占用读模式的读写锁.可是仅仅能一个线程占用写模式的读写锁. 1. 当读写锁是写加锁状态时,在这个锁被解锁之前,全部试图对这个锁加锁的线程都会被堵塞 ...
- Linux线程同步
1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...
- linux kernel RCU 以及读写锁
信号量有一个很明显的缺点,没有区分临界区的读写属性,读写锁允许多个线程进程并发的访问临界区,但是写访问只限于一个线程,在多处理器系统中允许多个读者访问共享资源,但是写者有排他性,读写锁的特性如下:允许 ...
随机推荐
- POJ 1410 判断线段与矩形交点或在矩形内
这个题目要注意的是:给出的矩形坐标不一定是按照左上,右下这个顺序的 #include <iostream> #include <cstdio> #include <cst ...
- 在Ubuntu 16.04中搭建RobotFramework环境
1.搭建RF环境 2.安装RF相关库 3.查看RF case 4.设置环境变量 相关知识点:pip --proxy=http://xx.xx.xx.xx:xx install 包名,使用pip的-- ...
- buu crypto 凯撒?替换?呵呵!
一. 以为是简单的凯撒加密,但是分析Ascill表,发现毫无规律,意味着要爆破出所有可能.只能用在线工具来弄了,脚本是不可能写的(狗头) 找到了,但是提交不成功,需要变成小写,用脚本转换一下,同时很坑 ...
- PHPCMSV9版本代码审计学习
学习代码审计,自己简单记录一下.如有错误望师傅斧正. PHPCMS预备知识 PHPCMS是采用MVC设计模式开发,基于模块和操作的方式进行访问,采用单一入口模式进行项目部署和访问,无论访问任何一个模块 ...
- Python报错“UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)”的解决办法
最近在用Python处理中文字符串时,报出了如下错误: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 0: ...
- python使用笔记22--mock接口开发
1.mock接口开发 mock是模拟一个接口的意思 为了不阻止测试,开发一个接口,返回你想要的数据,模拟各种场景 需要安装第三方模块flask,flask是web轻量级开发框架 1.1 flask p ...
- Java中为什么notify()可能导致死锁,而notifyAll()则不会(针对生产者-消费者模式)
1.先说两个概念:锁池 和 等待池 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线 ...
- HDFS学习总结之安装
HDFS linux安装总结(基于hadoop-2.6.0-cdh5.7.0 伪分部安装) 1.jdk安装 1) 直接下载jdk包放到安装目录即可(jdk-8u131-linux-x64.tar.gz ...
- 超详细!Vuex手把手教程
目录 1,前言 2,Vuex 是什么 3,5大属性说明 4,state 4.1 直接访问 4.1 使用mapState映射 5,getters 5.1 先在vuex中定义getters 5.2 直接获 ...
- Java 将Word转为XML,XML转为Word的方法
本文介绍将Word和XML文档进行双向互转的方法.转换时,Word支持.docx/.doc等格式. 代码环境如下: Word测试文档:.docx或.doc 编译环境:IntelliJ IDEA JDK ...