当前位置:网站首页>線程同步之讀寫鎖
線程同步之讀寫鎖
2022-06-26 03:57: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會搶到鎖先進行寫操作。
边栏推荐
- An error occurred using the connection to database 'on server' 10.28.253.2‘
- 线程同步之条件变量
- 【LOJ#6718】九个太阳「弱」化版(循环卷积,任意模数NTT)
- ABP framework Practice Series (III) - domain layer in depth
- Yolov5 improvements: replace the backbone
- Slide the menu of uni app custom components left and right and click switch to select and display in the middle
- Detr3d multi 2D picture 3D detection framework
- Dix critères de base importants pour les essais de débogage de logiciels
- . Net core learning journey
- 软件调试测试的十大重要基本准则
猜你喜欢

开源!ViTAE模型再刷世界第一:COCO人体姿态估计新模型取得最高精度81.1AP

Camera-CreateCaptureSession

Ten important basic principles of software debugging and testing

评价——层次分析

Uni app custom navigation bar component

捕获数据包(Wireshark)

ABP framework Practice Series (II) - Introduction to domain layer

. Net core learning journey

线程同步之条件变量

(15) Blender source code analysis flash window display menu function
随机推荐
Small record of neural network learning 71 - tensorflow2 deep learning with Google Lab
816. fuzzy coordinates
Webrtc series - 7-ice supplement of network transmission preference and priority
Uni app swiper rotation chart (full screen / card)
bubble sort
优化——多目标规划
Camera memory memory leak analysis (III)
2022.6.24-----leetcode. five hundred and fifteen
软件调试测试的十大重要基本准则
评价——层次分析
Concept and implementation of QPS
Go time package: second, millisecond, nanosecond timestamp output
神经网络学习小记录71——Tensorflow2 使用Google Colab进行深度学习
763. dividing alphabetic intervals
线程同步之条件变量
力扣79单词搜索
Uni app custom navigation bar component
Ieda suddenly cannot find compact middle packages
EF core Basics
go time包:秒、毫秒、纳秒时间戳输出