读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步,

和互斥量不同的是:互斥量会把试图进入已保护的临界区的线程都阻塞;然而读写锁会视当前进入临界区的线程和请求进入临界区的线程的属性来判断是否允许线程进入。

相对互斥量只有加锁和不加锁两种状态,读写锁有三种状态:读模式下的加锁,写模式下的加锁,不加锁

读写锁的使用规则:

  • 只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁;
  • 只有读写锁处于不加锁状态时,才能进行写模式下的加锁;

读写锁也称为共享-独占(shared-exclusive)锁,当读写锁以读模式加锁时,它是以共享模式锁住,当以写模式加锁时,它是以独占模式锁住。读写锁非常适合读数据的频率远大于写数据的频率从的应用中。这样可以在任何时刻运行多个读线程并发的执行,给程序带来了更高的并发度。

需要提到的是:读写锁到目前为止仍然不是属于POSIX标准,本文讨论的读写锁函数都是有Open Group定义的的。例如下面是在我机器上,编译器是gcc version 4.4.6,关于读写锁的定义是包含在预处理命令中的:

  1. #if defined __USE_UNIX98 || defined __USE_XOPEN2K
  2. ... 读写锁相关函数声明...
  3. #endif

1读写锁的初始化和销毁

  1. /* Initialize read-write lock  */
  2. int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
  3. __const pthread_rwlockattr_t *__restrict __attr);
  4. /* Destroy read-write lock */
  5. extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
  6. 返回值:成功返回0,否则返回错误代码

上面两个函数分别由于读写锁的初始化和销毁。和互斥量,条件变量一样,如果读写锁是静态分配的,可以通过常量进行初始化,如下:

  1. pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

也可以通过pthread_rwlock_init()进行初始化。对于动态分配的读写锁由于不能直接赋值进行初始化,只能通过这种方式进行初始化。pthread_rwlock_init()第二个参数是读写锁的属性,如果采用默认属性,可以传入空指针NULL。

那么当不在需要使用时及释放(自动或者手动)读写锁占用的内存之前,需要调用pthread_rwlock_destroy()进行销毁读写锁占用的资源。

2读写锁的属性设置

  1. /* 初始化读写锁属性对象 */
  2. int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr);
  3. /* 销毁读写锁属性对象 */
  4. int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);
  5. /* 获取读写锁属性对象在进程间共享与否的标识*/
  6. int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * __restrict __attr,
  7. int *__restrict __pshared);
  8. /* 设置读写锁属性对象,标识在进程间共享与否  */
  9. int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, int __pshared);
  10. 返回值:成功返回0,否则返回错误代码

这个属性设置和互斥量的基本一样,具体可以参考互斥量的设置互斥量的属性设置

3读写锁的使用

  1. /* 读模式下加锁  */
  2. int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
  3. /* 非阻塞的读模式下加锁  */
  4. int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
  5. # ifdef __USE_XOPEN2K
  6. /*  限时等待的读模式加锁 */
  7. int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
  8. __const struct timespec *__restrict __abstime);
  9. # endif
  10. /* 写模式下加锁  */
  11. int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
  12. /* 非阻塞的写模式下加锁 */
  13. int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
  14. # ifdef __USE_XOPEN2K
  15. /* 限时等待的写模式加锁 */
  16. int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
  17. __const struct timespec *__restrict __abstime);
  18. # endif
  19. /* 解锁 */
  20. int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
  21. 返回值:成功返回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()函数进行释放该读写锁。

下面是测试代码:

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <unistd.h>
  4. #include <pthread.h>
  5. using namespace std;
  6. struct{
  7. pthread_rwlock_t rwlock;
  8. int product;
  9. }sharedData = {PTHREAD_RWLOCK_INITIALIZER, 0};
  10. void * produce(void *ptr)
  11. {
  12. for (int i = 0; i < 5; ++i)
  13. {
  14. pthread_rwlock_wrlock(&sharedData.rwlock);
  15. sharedData.product = i;
  16. pthread_rwlock_unlock(&sharedData.rwlock);
  17. sleep(1);
  18. }
  19. }
  20. void * consume1(void *ptr)
  21. {
  22. for (int i = 0; i < 5;)
  23. {
  24. pthread_rwlock_rdlock(&sharedData.rwlock);
  25. cout<<"consume1:"<<sharedData.product<<endl;
  26. pthread_rwlock_unlock(&sharedData.rwlock);
  27. ++i;
  28. sleep(1);
  29. }
  30. }
  31. void * consume2(void *ptr)
  32. {
  33. for (int i = 0; i < 5;)
  34. {
  35. pthread_rwlock_rdlock(&sharedData.rwlock);
  36. cout<<"consume2:"<<sharedData.product<<endl;
  37. pthread_rwlock_unlock(&sharedData.rwlock);
  38. ++i;
  39. sleep(1);
  40. }
  41. }
  42. int main()
  43. {
  44. pthread_t tid1, tid2, tid3;
  45. pthread_create(&tid1, NULL, produce, NULL);
  46. pthread_create(&tid2, NULL, consume1, NULL);
  47. pthread_create(&tid3, NULL, consume2, NULL);
  48. void *retVal;
  49. pthread_join(tid1, &retVal);
  50. pthread_join(tid2, &retVal);
  51. pthread_join(tid3, &retVal);
  52. return 0;
  53. }

测试结果如下:

  1. consume1:0
  2. consume2:0
  3. consume2:0
  4. consume1:1
  5. consume2:1
  6. consume1:2
  7. consume2:2
  8. consume1:3
  9. consume2:3
  10. consume1:4

如果把consume1的解锁注释掉,如下:

  1. void * consume1(void *ptr)
  2. {
  3. for (int i = 0; i < 5;)
  4. {
  5. pthread_rwlock_rdlock(&sharedData.rwlock);
  6. cout<<"consume1:"<<sharedData.product<<endl;
  7. //pthread_rwlock_unlock(&sharedData.rwlock);
  8. ++i;
  9. sleep(1);
  10. }
  11. }

程序的执行结果如下:

  1. consume1:0
  2. consume2:0
  3. consume2:0
  4. consume1:0
  5. consume2:0
  6. consume1:0
  7. consume2:0
  8. consume1:0
  9. consume2:0
  10. consume1:0

从执行结果可以看出Linux 2.6.18提供的读写锁函数是优先考虑等待读模式占用锁的线程,这种实现的一个很大缺陷就是出现写入线程饿死的情况。

Jun 26, 2013 AM 00:08 @Library

原文:http://blog.csdn.net/anonymalias/article/details/9174595

Linux线程同步之读写锁(rwlock)的更多相关文章

  1. linux线程同步(3)-读写锁

    一.概述                                                    读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...

  2. UNIX环境高级编程——线程同步之读写锁以及属性

    读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 互 ...

  3. 线程同步——用户模式下线程同步——Slim读写锁实现线程同步

    //Slim读/写锁实现线程同步 SRWlock 的目的和关键段相同:对同一资源进行保护,不让其它线程访问. 但是,与关键段不同的是,SRWlock允许我们区分哪些想要读取资源的线程(读取者线程) 和 ...

  4. Linux系统编程 —读写锁rwlock

    读写锁是另一种实现线程间同步的方式.与互斥量类似,但读写锁将操作分为读.写两种方式,可以多个线程同时占用读模式的读写锁,这样使得读写锁具有更高的并行性. 读写锁的特性为:写独占,读共享:写锁优先级高. ...

  5. linux c编程:读写锁

    什么是读写锁读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的 为什么需要读写锁有时候,在多线程中,有一些公共数据修改的 ...

  6. 嵌入式 Linux线程同步读写锁rwlock示例

    读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁.1. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞:2. ...

  7. linux线程间同步(1)读写锁

    读写锁比mutex有更高的适用性,能够多个线程同一时候占用读模式的读写锁.可是仅仅能一个线程占用写模式的读写锁. 1. 当读写锁是写加锁状态时,在这个锁被解锁之前,全部试图对这个锁加锁的线程都会被堵塞 ...

  8. Linux线程同步

    1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...

  9. linux kernel RCU 以及读写锁

    信号量有一个很明显的缺点,没有区分临界区的读写属性,读写锁允许多个线程进程并发的访问临界区,但是写访问只限于一个线程,在多处理器系统中允许多个读者访问共享资源,但是写者有排他性,读写锁的特性如下:允许 ...

随机推荐

  1. 视频云峰会|“科技 X 艺术” 的颗粒度体验是什么?

    科技日新月异,交互艺术新门类也随之蓬勃,当代艺术创作者不断凭借其想象力和跨学科能力,致力科技与艺术的融合创作. 7 月 10 日,在北京,2021 阿里云视频云全景创新峰会暨全球视频云创新挑战赛决赛颁 ...

  2. 在CentOS7环境下部署weblogic集群

    一)环境准备 服务器操作版本系统 CentOS7 weblogic版本包 weblogic1036_generic.jar(weblogic11g) JDK jdk-8u191-linux-x64.t ...

  3. 单片机与PLC的区别?

    单片机顾名思义集成在一个芯片内的计算机系统,又叫单片微控制器,英文:mcu,具有计算机的全部功能.PLC是英文Programmable Logic Controller的简称,翻译过来就是可编程逻辑控 ...

  4. 解决ionic5多个模态关闭一个其他不显示的问题

    ionic5 modal使用过程中,在模态窗中打开另外一个模态窗,浏览器中显示正常,但是andorid8系统真机调试时,关闭最上层模态窗,上级模态窗DOM中存在,但是不显示. 原因是android版本 ...

  5. HAL库直流电机编码测速(L298N驱动)笔记

    主函数开始后的处理流程: 1.外设初始化:HAL_Init() 2.系统时钟配置 RCC振荡器初始化:HAL_RCC_OsConfig() RCC时钟初始化:HAL_RCC_ClockConfig() ...

  6. Java | 变量 & 常量

    变量 Java是一种强类型语言,每个变量都必须声明其数据类型,变量本质上就是代表一个"可操作的存储的空间",在定义之后空间位置是确定的,但是里面放置什么值是不确定的,我们操作的时候 ...

  7. java基础---java8后新特性

    1. java9 新特性 模块化的使用 减少内存的开销. 可简化各种类库和大型应用的开发和维护. 安全性,可维护性,提高性能. 在 module-info.java 文件中,我们可以用新的关键词mod ...

  8. C语言:int -32768-32767

    c语言中int的表示范围是-32768~32767!这得从二进制的原码说起:如果以最高位为符号位,二进制原码最大为0111111111111111=2的15次方减1=32767最小为111111111 ...

  9. MVC框架介绍分析

    相信绝大多数学习过Javaweb的人都知道一个系统的模式--Spring模式,以这么模式中为基础,衍生出各种各样的新的模式,其中最重要的就是Spring下的Spring MVC MVC是Xerox P ...

  10. 【16位RAW图像处理三】直方图均衡化及局部直方图均衡用于16位图像的细节增强。

    通常我们生活中遇到的图像,无论是jpg.还是png或者bmp格式,一般都是8位的(每个通道的像素值范围是0-255),但是随着一些硬件的发展,在很多行业比如医疗.红外.航拍等一些场景下,拥有更宽的量化 ...