当前位置:网站首页>线程同步之读写锁
线程同步之读写锁
2022-06-26 03:56:00 【StudyWinter】
与互斥量类似,但读写锁允许更高的并行性。其特性为: 写独占,读共享。
1 读写锁状态
特别强调: 读写锁只有一把, 但其具备两种状态:
1 读模式下加锁状态 (读锁);
2 写模式下加锁状态 (写锁) 。
2 读写锁特性
1 读写锁是“写模式加锁”时, 解锁前,所有对该锁加锁的线程都会被阻塞;
2 读写锁是“读模式加锁”时, 如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞;
3 读写锁是“读模式加锁”时, 既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求。优先满足写模式锁。 读锁、写锁并行阻塞, 写锁优先级高 。
读写锁也叫共享-独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。 写独占、读共享。读写锁非常适合于对数据结构读的次数远大于写的情况。
主要函数
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
pthread_rwlock_rdlock(&rwlock); // try
pthread_rwlock_wrlock(&rwlock); // try
pthread_rwlock_unlock(&rwlock);
pthread_rwlock_destroy(&rwlock);以上函数都是成功返回0,失败返回错误号。
(1)pthread_rwlock_init 函数
初始化一把读写锁
pthread_rwlock_t rwlock;
// 方法1
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
// 参 2: attr 表读写锁属性,通常使用默认属性, 传 NULL 即可
// 方法2
rwlock = PTHREAD_RWLOCK_INITIALIZER;(2)pthread_rwlock_destroy 函数
销毁一把读写锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);(3)pthread_rwlock_rdlock 函数
以读方式请求读写锁。(常简称为:请求读锁)
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);(4)pthread_rwlock_wrlock 函数
以写方式请求读写锁。(常简称为:请求写锁)
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);(5)pthread_rwlock_unlock 函数
解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);(6)pthread_rwlock_tryrdlock 函数
非阻塞以读方式请求读写锁(非阻塞请求读锁)
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);(7)pthread_rwlock_trywrlock函数
非阻塞以写方式请求读写锁(非阻塞请求写锁)
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);3 两种死锁
是使用锁不恰当导致的现象:
1. 对一个锁反复lock。
2. 两个线程,各自持有一把锁,请求另一把。

4 读写锁案例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
// 全局共享资源
int counter;
// 全局读写锁,初始化
pthread_rwlock_t rwlock;
// rwlock = PTHREAD_RWLOCK_INITIALIZER;
// 任务:3个线程不同时写同一资源,5个线程不同时读同一资源
// 写
void *do_write(void *arg)
{
int t = 0;
int i = (int)arg;
int res = 0;
while (1)
{
// 加锁,写锁独占
res = pthread_rwlock_wrlock(&rwlock);
if (res != 0)
{
fprintf(stderr, "pthread_rwlock_wrlock error:%s\n", strerror(res));
exit(1);
}
t = counter;
usleep(10000);
// 修改就是写
printf("------write:%d, %lu, counter = %d, ++counter = %d\n", i, pthread_self(), t, ++counter);
// 解锁
res = pthread_rwlock_unlock(&rwlock);
if (res != 0)
{
fprintf(stderr, "pthread_rwlock_unlock error:%s\n", strerror(res));
exit(1);
}
usleep(10000);
}
return NULL;
}
// 读
void *do_read(void *arg)
{
int res = 0;
int i = (int)arg;
while (1) {
// 加锁,读共享
res = pthread_rwlock_rdlock(&rwlock);
if (res != 0)
{
fprintf(stderr, "pthread_rwlock_rdlock error:%s\n", strerror(res));
exit(1);
}
usleep(10000);
// 修改就是写
printf("==========================================read:%d, %lu, counter = %d\n", i, pthread_self(), counter);
// 解锁
res = pthread_rwlock_unlock(&rwlock);
if (res != 0)
{
fprintf(stderr, "pthread_rwlock_unlock error:%s\n", strerror(res));
exit(1);
}
usleep(10000);
}
return NULL;
}
int main(int argc, char **argv)
{
int i;
// 8个线程
pthread_t tid[8];
// 初始化读写锁
int res = pthread_rwlock_init(&rwlock, NULL);
if (res != 0)
{
fprintf(stderr, "pthread_rwlock_init error:%s\n", strerror(res));
exit(1);
}
// 初始化线程
// 写线程
for (i = 0; i < 3; i++)
{
res = pthread_create(&tid[i], NULL, do_write, (void *)i);
if (res != 0)
{
fprintf(stderr, "pthread_create write error:%s\n", strerror(res));
exit(1);
}
}
// 读线程
for (i = 3; i < 8; i++)
{
res = pthread_create(&tid[i], NULL, do_read, (void *)i);
if (res != 0)
{
fprintf(stderr, "pthread_create read error:%s\n", strerror(res));
exit(1);
}
}
// 回收子线程
for (i = 0; i < 8; i++)
{
res = pthread_join(tid[i], NULL);
if (res != 0)
{
fprintf(stderr, "pthread_join error:%s\n", strerror(res));
exit(1);
}
}
// 销毁读写锁
res = pthread_rwlock_destroy(&rwlock);
if (res != 0)
{
fprintf(stderr, "pthread_join error:%s\n", strerror(res));
exit(1);
}
return 0;
}执行

程序输出飞快,随便截个图,如上图。
由于读共享,写独占。写锁优先级高。前面5个read一定先于后面的write到达的,不然write会抢到锁先进行写操作。
边栏推荐
- 判断两个集合的相同值 ||不同值
- [Flink] a brief analysis of the writing process of Flink sort shuffle
- Sorting out the knowledge points of the renderview renderobject parentdata of the shuttle
- MySQL common statements
- 2022.6.25-----leetcode. Sword finger offer 091
- "Renegotiation" agreement
- Link monitoring pinpoint
- 816. fuzzy coordinates
- Chrome page recording and playback function
- Ten important basic principles of software debugging and testing
猜你喜欢

使用SOAPUI访问对应的esb工程

力扣 515. 在每个树行中找最大值

Non H5 end of uni app, regional setting of status bar on the top of mobile phone

Oracle technology sharing Oracle 19.14 upgrade 19.15

User control custom DependencyProperty

An error occurred using the connection to database 'on server' 10.28.253.2‘

EF core Basics

软件调试测试的十大重要基本准则

ASP. Net startup and running mechanism

Open Camera异常分析(一)
随机推荐
Matplotlib multi line chart, dot scatter chart
Custom parameter QR code picture combined with background picture to generate new picture node environment
Sorting out the knowledge points of the renderview renderobject parentdata of the shuttle
【Flink】Flink源码分析——批处理模式JobGraph的创建
Webrtc series - 7-ice supplement of network transmission preference and priority
816. 模糊坐标
Is the waiting insurance record a waiting insurance evaluation? What is the relationship between the two?
Ten important basic principles of software debugging and testing
优化——多目标规划
Uni app, the text implementation expands and retracts the full text
Asynctask multiple simultaneous use methods
1.基础关
Flask入门
三元损失英文版
asp.net网页选择身份进行登录的简单代码,asp连接数据库,使用asp:Panel、asp:DropDownList控件
面了个字节拿25k出来的测试,算是真正见识到了基础的天花板
EF core Basics
Question brushing record day01
The style of the mall can also change a lot. DIY can learn about it
go time包:秒、毫秒、纳秒时间戳输出