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

http://www.cnblogs.com/yuuyuu/p/5143881.html

一.概述                                                   

读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。读写锁有以下特点:

1.如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿

2.如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!

二.函数接口                                           

1.创建读写锁

1.1:宏常量初始化

1 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

1.2:函数初始化

1 #include <pthread.h>
2 
3 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

rwlock:读写锁的pthread_rwlock_t结构指针

attr:读写锁的属性结构指针。不需要别的属性默认为NULL。

2.读写锁加锁与解锁

1 #include <pthread.h>
2 
3 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
4 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
5 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

rwlock:创建的读写锁指针

3.其他类型的加锁

复制代码
1 #include <pthread.h>
2 #include <time.h>
3 
4 
5 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
6 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
7 
8 int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
9 int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
复制代码

try类函数加锁:如果获取不到锁,会立即返回错误EBUSY

timed类函数加锁:如果规定的时间内获取不到锁,会返回ETIMEDOUT错误!

4.销毁读写锁

1 #include <pthread.h>
2 
3 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

三.简单的例子                                        

创建4个线程,2个线程读锁,2个线程写锁,观察4个线程进入临界区的顺序

复制代码
 1 /**
 2  * @file pthread_rwlock.c
 3  */
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <unistd.h>
 9 #include <pthread.h>
10 
11 /* 初始化读写锁 */
12 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
13 /* 全局资源 */
14 int global_num = 10;
15 
16 void err_exit(const char *err_msg)
17 {
18     printf("error:%s\n", err_msg);
19     exit(1);
20 }
21 
22 /* 读锁线程函数 */
23 void *thread_read_lock(void *arg)
24 {
25     char *pthr_name = (char *)arg;
26 
27     while (1)
28     {
29         /* 读加锁 */
30         pthread_rwlock_rdlock(&rwlock);
31 
32         printf("线程%s进入临界区,global_num = %d\n", pthr_name, global_num);
33         sleep(1);
34         printf("线程%s离开临界区...\n", pthr_name);
35 
36         /* 读解锁 */
37         pthread_rwlock_unlock(&rwlock);
38 
39         sleep(1);
40     }
41 
42     return NULL;
43 }
44 
45 /* 写锁线程函数 */
46 void *thread_write_lock(void *arg)
47 {
48     char *pthr_name = (char *)arg;
49 
50     while (1)
51     {
52         /* 写加锁 */
53         pthread_rwlock_wrlock(&rwlock);
54 
55         /* 写操作 */
56         global_num++;
57         printf("线程%s进入临界区,global_num = %d\n", pthr_name, global_num);
58         sleep(1);
59         printf("线程%s离开临界区...\n", pthr_name);
60 
61         /* 写解锁 */
62         pthread_rwlock_unlock(&rwlock);
63 
64         sleep(2);
65     }
66 
67     return NULL;
68 }
69 
70 int main(void)
71 {
72     pthread_t tid_read_1, tid_read_2, tid_write_1, tid_write_2;
73 
74     /* 创建4个线程,2个读,2个写 */
75     if (pthread_create(&tid_read_1, NULL, thread_read_lock, "read_1") != 0)
76         err_exit("create tid_read_1");
77 
78     if (pthread_create(&tid_read_2, NULL, thread_read_lock, "read_2") != 0)
79         err_exit("create tid_read_2");
80 
81     if (pthread_create(&tid_write_1, NULL, thread_write_lock, "write_1") != 0)
82         err_exit("create tid_write_1");
83 
84     if (pthread_create(&tid_write_2, NULL, thread_write_lock, "write_2") != 0)
85         err_exit("create tid_write_2");
86 
87     /* 随便等待一个线程,防止main结束 */
88     if (pthread_join(tid_read_1, NULL) != 0)
89         err_exit("pthread_join()");
90 
91     return 0;
92 }
复制代码

2个线程函数的临界区里面都sleep(1),测试给足够的时间看其他线程能不能进来。64行,写锁函数里面,sleep(2),因为写锁请求会阻塞后面的读锁,2个写锁一起请求会让读锁饥饿,所以比39行的sleep(1)多一秒!

编译运行:

可以看到,读锁可以一起进入临界区,而写锁在临界区里面等1秒都不会有其他线程能进来!!!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384006.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux线程同步(5)-屏障

http://www.cnblogs.com/yuuyuu/p/5152560.html 一.概述 barrier(屏障)与互斥量&#xff0c;读写锁&#xff0c;自旋锁不同&#xff0c;它不是用来保护临界区的。相反&#xff0c;它跟条件变量一样&#xff0c;是用来协同多…

Linux多线程与同步

https://www.cnblogs.com/freedomabcd/p/7774743.html 典型的UNIX系统都支持一个进程创建多个线程(thread)。在Linux进程基础中提到&#xff0c;Linux以进程为单位组织操作&#xff0c;Linux中的线程也都基于进程。尽管实现方式有异于其它的UNIX系统&#xff0c;但Linux的多线程…

内存管理(二)

页面置换算法 当发生缺页中断的时候, 系统会在内存中选择一个页面将其换出内存, 而当换出内存的时候如果该页面的内容在内存中发生修改,则必须将该新数据重新写回到磁盘, 然后再将需要换进的数据覆盖掉原来的数据, 而当该数据在内存中没有被修改的时候, 此时就直接用需要换进的…

数据链路层:基本概念

数据链路层的定义 对数据链路层有对上的网络层接口. 对下提供物理层的接口. 定义合适的传输差错率 对传输流进行管理, 以免快速的传输的数据被淹没. 比如发送端发送信号太快, 接受方接受速度较慢, 此时数据链路层就需要提供一定的功能解决这个问题 物理层上传输的基本单元是…

数据链路层: 可靠性传输 六个协议

可靠性传输 1. 差错控制 发送方将数据帧发送, 但是当发送方发送的是一个 1的时候此时接受方却接受的是一个 0. (1)校验 接收方如果帧校验接受到的帧没有问题, 则对发送方发送一个肯定性的确认, 当对这个数据帧进行校验发现这个帧有问题的时候, 此时接受方一种是将这个数据帧…

c语言实现配置文件的读写

配置文件的格式如下&#xff1a; key1 value1 key2 value2 . . . 名值对以一个链接&#xff0c;一条记录以换行符分割 头文件&#xff1a; #include<stdio.h> #include<stdlib.h> #include <string.h> 函数原型&#xff1a; void trim(char *strIn, char *…

数据链路层: HDLC

一. 协议机 发送方和接收方. 同时有限状态机把协议形式化为一个四元组 (S,M,I,T), 其中你S表示进程和信道可能进入的集合, M 表示数据帧的状态, I 表示进程的初始状态, T 表示两两状态之间的转化. 每个系统状态可以分为发送状态, 接受状态和信道状态. 把状态用一个点进行表示,…

bob-tong 字符串函数之Strtok()函数

https://www.cnblogs.com/Bob-tong/p/6610806.html Strtok()函数详解&#xff1a; 该函数包含在"string.h"头文件中 函数原型&#xff1a; char* strtok (char* str,constchar* delimiters ); 函数功能&#xff1a;   切割字符串&#xff0c;将str切分成一个个子…

数据链路层:SLIP(串型线路IP) PPP(点对点协议)

SLIP 没有差错控制, 传输时必须知道对方IP, 传输使用于低速业务 19.2k.应用非常受限 PPP协议 1. PPP协议功能 处理错误检测 支持多协议(IP, IPX, DECnet 等) 连接时允许协商 IP 地址 允许身份验证 2. PPP 的组成 串型链路上封装数据报, 即支持异步链路也支持面向 比特…

strpbrk函数

http://blog.csdn.net/tommy_wxie/article/details/7554332 函数原型&#xff1a;extern char *strpbrk(char *str1, char *str2) 参数说明&#xff1a;str1待比较的字符串&#xff0c;str2为指定被搜索的字符串。 所在库名&#xff1a;#include <string.h> …

网络层网络层服务及其 IP 地址

ARP 协议功能 将 IP 地址通过广播(一个网段, 不能跨路由器), 目标 MAC 地址是FFFFFFFF 解析目标IP地址的 MAC 地址. IP 协议 网络层的一个协议, 是一个协议的统称, 包括 ARP(地址解析协议) 协议, ICMP(网络控制报文协议) 协议, IGMP(网际组管理协议) 协议. 其中 ICMP 和 IG…

传输层:IP 地址解析 路由转发

IP 地址与硬件地址 1. 地址解析 通过IP地址将其如何转换为 MAC 地址.解决同一个局域网上的主机或路由的 IP 地址和硬件地址的映射问题. 即以太网上除了主机还有路由. 即如果发出的请求所有的主机都没有做出相应, 那么该以太网上的路由会对其做出响应. (1) 以太网内部主机与…

网络层:构成超网(CIDR)

CIDR构成超网 CIDR消除了原来的传统的 A,B, C, D类地址, 使用了各种网络前缀来代替原来分类地址中的网络号和子网号, IP 地址由原来的三级分类又变成了两级分类. 其中网络号和子网号是一个随机的长度. 其中 CIDR 也可以使用 / 的形式来表示, 其中在 / 前面写上网络前缀的位数.…

网络层:网关协议

一. 网关 所谓的网管即就是之前路由器的名字, 即路由器和网关是一个东西 二. 内部网关协议 1. RIP协议 路由信息协议 RIP 是内部网关协议 IGP中最先得到的广泛使用的协议. 同时 RIP 是一种分布式基于距离向量的路由选择协议. RIP 协议要求网络中的每一个路由都必须维护自己…

网络基础: 浅析应用层一

应用层 1. http协议 在 http 中协议分为了协议方案名, 登录信息名, 服务器地址, 服务器端口号(http协议绑定的端口号), 文件类型, 查询的字符串, 片段标识位 2. http 请求协议格式 httpp 总共分为三大部分, 其中首行即就是第一部分, 分为三个区域, 第一去个区域是请方法, 第…

socket 编程篇六之IPO多路复用-select poll epoll

http://blog.csdn.net/woxiaohahaa/article/details/51498951 文章参考自&#xff1a;http://blog.csdn.net/tennysonsky/article/details/45745887&#xff08;秋叶原 — Mike VS 麦克《Linux系统编程——I/O多路复用select、poll、epoll的区别使用》&#xff09; 此外&#x…

浅谈传输层

1. 传输层的作用 在传输层中有两个特别重要的协议 TCP/UDP . 以快递员送快递为例说明这个问题吧. 在进行包裹传输的过程中快递员需要根据快递上的目的地址(目的计算机)来投递包裹(IP数据报), 加入在快递单上只写了收件人的所在地, 所在单位, 而只写了收件人的姓没有写收件人的…

I/O复用的 select poll和epoll的简单实现

http://www.cnblogs.com/wj9012/p/3876734.html 一个tcp的客户端服务器程序 服务器端不变&#xff0c;客户端通过I/O复用轮询键盘输入与socket输入&#xff08;接收客户端的信息&#xff09; 服务器端&#xff1a; 1 /*服务器:2 1.客户端关闭后&#xff0c;服务器再向客户端发送…

TCP相关代码

TCP 基础代码 //tcp_server.c #include<stdio.h> #include<error.h> #include<sys/types.h> #include<string.h> #include<unistd.h> #include<sys/socket.h> #include<netinet/in.h> #include <arpa/inet.h> #include<st…

几种并发服务器模型的实现:多线程,多进程,select,poll,epoll

http://www.cnblogs.com/wj9012/p/3879605.html 客户端使用select模型&#xff1a; 1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include <errno.h>5 #include <sys/types.h>6 #include <sys/socket.h>7 #include …