读写锁

索引:

  1. 初始化一个读写锁pthread_rwlock_init
  2. 读锁定读写锁      pthread_rwlock_rdlock
  3. 非阻塞读锁定  pthread_rwlock_tryrdlock
  4. 写锁定读写锁      pthread_rwlock_wrlock
  5. 非阻塞写锁定      pthread_rwlock_trywrlock
  6. 解锁读写锁         pthread_rwlock_unlock
  7. 释放读写锁         pthread_rwlock_destroy

读写锁是用来解决读者写者问题的,读操作可以共享,写操作是排他的,读可以有多个在读,写只有唯一个在写,同时写的时候不允许读。

具有强读者同步和强写者同步两种形式:

强读者同步:当写者没有进行写操作,读者就可以访问;

强写者同步:当所有写者都写完之后,才能进行读操作,读者需要最新的信息,一些事实性较高的系统可能会用到该所,比如定票之类的。

1.初始化一个读写锁pthread_rwlock_init

#include <pthread.h>

  int pthread_rwlock_init(pthread_rwlock_t *rwlock, \ const pthread_rwlockattr_t *attr);

  返回值:函数成功返回0;任何其他返回值都表示错误

初始化rwlock指定的读写锁,它的属性被参数attr指定。如果attr的值为NULL,初始化读写锁时使用缺省的读写锁属性。其效果和attr指向一个缺省的读写锁属性对象是一样的。

成功初始化后,读写锁的状态为非锁定的。

对一个已经初始化过的读写锁调用pthread_rwlock_init函数会产生不可预测的后果。使用一个未经初始化的读写锁也会产生不可预测的后果。

如果需要缺省属性的读写锁,可以用宏PTHREAD_RWLOCK_INITIALIZER初始化静态的读写锁变量。但是,静态初始化读写锁不进行错误检查。如:

pthread_rwlock_t rwlock = PTHREASD_RWLOCK_INITIALIZER;

 获取读写锁的读锁操作:分为阻塞式获取和非阻塞式获取,如果读写锁由一个写者持有,则读线程会阻塞直至写入者释放读写锁。

2.读锁定读写锁pthread_rwlock_rdlock

  #include <pthread.h>

  int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

  返回值:函数成功返回0;任何其他返回值都表示错误

函数在rwlock读写锁上进行读锁定。

如果一个线程写锁定了读写锁,调用pthread_rwlock_rdlock函数的线程将无法读锁定读写锁,并将被阻塞,直到线程可以读锁定这个读写锁为止。

如果一个线程写锁定了读写锁后又调用pthread_rwlock_rdlock函数来读锁定同一个读写锁,结果将无法预测。

标准中没有指定当没有线程写锁定这个读写锁,但有线程试图写锁定而被阻塞在这个读写锁上时,当前线程是否能读锁定读写锁。大多数线程库往往优先考虑激活试图写锁定而被阻塞的线程,这样做是为了防止试图写锁定而被阻塞的线程长时间得不到调度。

一个线程可能对一个读写锁进行了多次读锁定(即成功调用了pthread_rwlock_rdlock()函数多次)。如果是这样的,线程必须调用pthread_rwlock_unlock()函数对读写锁进行同样次数的解锁。

当一个读写锁被读锁定了,而一个线程阻塞在这个读写锁上时,如果这时来了一个信号,那么当线程从信号处理程序中返回时,将继续阻塞在这个读写锁上。就好象线程没有被中断过。

3.非阻塞读锁定pthread_rwlock_tryrdlock

  #include <pthread.h>

  int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

  返回值:函数成功返回0;任何其他返回值都表示错误

pthread_rwlock_tryrdlock()函数和pthread_rwlock_rdlock函数的功能相近,不同的是,当已有线程写锁定读写锁,或是有试图写锁定的线程被阻塞时,pthread_rwlock_tryrdlock函数失败返回。

获取读写锁的写锁操作:分为阻塞和非阻塞,如果对应的读写锁被其它写者持有,或者读写锁被读者持有,该线程都会阻塞等待。

4.写锁定读写锁pthread_rwlock_wrlock

  #include <pthread.h>

  int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

  返回值:函数成功返回0;任何其他返回值都表示错误

写锁定读写锁rwlock。如果没有线程读或写锁定读写锁rwlock,当前线程将写锁定读写锁rwlock。否则线程将被阻塞,直到没有线程锁定这个读写锁为止。

如果调用这个函数之前,本线程已经读或写锁定了这个读写锁,那么pthread_rwlock_wrlock函数运行的结果是不可预测的。

读写锁被解开以后,激活阻塞在读写锁上的线程时,往往优先考虑试图写锁定而被阻塞的线程,这样做是为了防止试图写锁定而被阻塞的线程长时间得不到调度。

当一个读写锁被写锁定了,而一个线程阻塞在这个读写锁上时,如果这时来了一个信号,那么当线程从信号处理程序中返回时,将继续阻塞在这个读写锁上。就好像线程没有被中断过。

5.非阻塞写锁定pthread_rwlock_trywrlock

  #include <pthread.h>

  int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

  返回值:函数成功返回0;任何其他返回值都表示错误

pthread_rwlock_trywrlock函数的功能和pthread_rwlock_wrlock函数相近。不同的是如果有其他线程锁定了读写锁,pthread_rwlock_trywrlock函数会失败返回。

6.解锁读写锁pthread_rwlock_unlock

  #include <pthread.h>

  int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

  返回值:函数成功返回0;任何其他返回值都表示错误

解锁一个读写锁。

调用pthread_rwlock_unlock函数之前必须调用pthread_rwlock_rdlock函数或pthread_rwlock_wrlock函数锁定读写锁。否则结果是不可预测的。

在pthread_rwlock_unlock函数被用来解锁对读写锁的读锁定后,如果本线程对这个读写锁还有其他读锁定,那么这个读写锁对本线程将继续保持读锁定状态。如果pthread_rwlock_unlock函数解开了当前线程在这个读写锁上的最后一个读锁定,那么当前线程将不再拥有对这个读写锁的读锁定。如果pthread_rwlock_unlock函数解开了这个读写锁上的最后一个锁定,那么这个读写锁将处在非锁定状态。

如果pthread_rwlock_unlock函数被用来解锁对读写锁的写锁定,那么函数返回后,这个读写锁将处在非锁定状态。

如果用pthread_rwlock_unlock函数解锁一个读写锁时,有多个线程在等待对这个读写锁进行写锁定,系统将用调度策略决定激活哪个线程对读写锁进行写锁定。

如果用pthread_rwlock_unlock函数解锁一个读写锁时,有多个线程在等待对这个读写锁进行读锁定,系统将用调度策略决定按什么顺序激活各个线程对读写锁进行读锁定。

如果用pthread_rwlock_unlock函数解锁一个读写锁时,有多个线程在等待对这个读写锁进行写锁定和读锁定,一般先激活需要写锁定的线程对读写锁进行写锁定(标准没有指定在这种情况下应该先激活写线程还是先激活读线程)。

7.释放读写锁pthread_rwlock_destroy

  #include <pthread.h>

  int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

  返回值:函数成功返回0;任何其他返回值都表示错误

释放读写锁rwlock,并释放这个读写锁占用的资源。一般情况下,pthread_rwlock_destroy函数将rwlock指向的互斥锁对象设置为非法值。

释放了一个读写锁之后,在pthread_rwlock_init重新初始化它之前,再使用这个读写锁会有不可预料的结果。

如果有线程锁定了某个读写锁,那么用pthread_rwlock_destroy()函数释放这个读写锁会引起不可预知的结果。

试图释放一个未初始化的读写锁会引起不可预知的结果。

总结(转):

互斥锁与读写锁的区别:

当访问临界区资源时(访问的含义包括所有的操作:读和写),需要上互斥锁;

当对数据(互斥锁中的临界区资源)进行读取时,需要上读取锁,当对数据进行写入时,需要上写入锁。

读写锁的优点:

对于读数据比修改数据频繁的应用,用读写锁代替互斥锁可以提高效率。因为使用互斥锁时,即使是读出数据(相当于操作临界区资源)都要上互斥锁,而采用读写锁,则可以在任一时刻允许多个读出者存在,提高了更高的并发度,同时在某个写入者修改数据期间保护该数据,以免任何其它读出者或写入者的干扰。

读写锁描述:

获取一个读写锁用于读称为共享锁,获取一个读写锁用于写称为独占锁,因此这种对于某个给定资源的共享访问也称为共享-独占上锁。

有关这种类型问题(多个读出者和一个写入者)的其它说法有读出者与写入者问题以及多读出者-单写入者锁。

pthread_rwlock_t读写锁函数说明的更多相关文章

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

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

  2. Linux 读写锁

    线程的读写锁函数: 1,读写锁的初始化与销毁,静态初始化的话,可以直接使用PTHREAD_RWLOCK_INITIALIZER. #include <pthread.h> int pthr ...

  3. pthread 读写锁

    pthread 读写锁 (Read Write Lock, rwlock) 把对共享资源的访问者分为读者和写者,读者仅仅对共享资源进行读访问,写者仅仅对共享资源进行写操作. 如果使用互斥量 mutex ...

  4. Linux线程同步之读写锁(rwlock)

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

  5. freeswitch APR库线程读写锁

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 线程读写锁在多线程服务中有重要的作用.对于读数据比写数据频繁的服务,用读写锁代替互斥锁可以提高效率. 由于A ...

  6. 读者写者问题继 读写锁SRWLock

    在<秒杀多线程第十一篇读者写者问题>文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法--读写锁SRWLock来解决这一 ...

  7. 多线程面试题系列(14):读者写者问题继 读写锁SRWLock

    在第十一篇文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法--读写锁SRWLock来解决这一问题.读写锁在对资源进行保护的同时,还 ...

  8. 转---秒杀多线程第十四篇 读者写者问题继 读写锁SRWLock

    在<秒杀多线程第十一篇读者写者问题>文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法——读写锁SRWLock来解决这一 ...

  9. 多线程 读写锁SRWLock

    在<秒杀多线程第十一篇读者写者问题>文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法——读写锁SRWLock来解决这一 ...

随机推荐

  1. Node.js权威指南 (6) - 在Node.js中操作文件系统

    6.1 同步方法与异步方法 / 856.2 对文件执行读写操作 / 86 6.2.1 文件的完整读写 / 86 6.2.2 从指定位置处开始读写文件 / 916.3 创建与读取目录 / 97 6.3. ...

  2. 【转】怎么在Foxmail回复/转发时使用签名?

    原文网址:http://kf.qq.com/faq/120322fu63YV130422yABZRZ.html Foxmail回复/转发时使用签名,可通过在模版中设置签名.如下版本操作方法: 一.fo ...

  3. SqlServer:CTE函数处理递归(WITH语法)

    我们在做分类处理的时候,总会遇到递归的处理,比如说地区就是一个例子,中国--北京--西城区,我们可以把这样的信息存储在一个数据表中,用ParentID区分根节点和叶子节点.假如我们要做导航,得到了”西 ...

  4. Lowest Common Ancestor of a Binary Tree——Leetcode

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...

  5. HDOJ/HDU 1321 Reverse Text(倒序输出~)

    Problem Description In most languages, text is written from left to right. However, there are other ...

  6. ZOJ 3761 Easy billiards 月赛E DFS

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3761 题目大意:给定n个位置的小球,小球的运动方向只能是水平或者 ...

  7. zoj 3656

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4879 代码: #include<cstdio> #inc ...

  8. Qt 线程基础(Thread Basics的翻译,线程的五种使用情况)

    Qt 线程基础(QThread.QtConcurrent等) 转载自:http://blog.csdn.net/dbzhang800/article/details/6554104 昨晚看Qt的Man ...

  9. 如何将位图格式图片文件(.bmp)生成geotiff格式图片?

    一.位图格式信息 位图BITMAPINFOHEADER 与BITMAPFILEHEADER: 先来看BITMAPINFOHEADER,只写几个主要的 biSize包含的是这个结构体的大小(包括颜色表) ...

  10. db4o官方停止支持及面向对象数据库的一些感想

    前一段时间试用了db4o,真心认为不错.但自己在国内搜索了一下,并没有找到不论什么一个专门的论坛和面向对象的数据库产品.深感这东西在国内并没有太普及. 但自己试用认为这个东东真心不错(当然也有自己的优 ...