(1) 讀寫鎖是幾把鎖
一把鎖
pthread_rwlock_t lock;
(2) 讀寫鎖的類型
讀鎖: 對內存做讀操作
寫鎖: 對內存做寫操作
(3) 讀寫鎖的特性:
線程A加讀鎖成功, 又來了三個線程, 做讀操作, 可以加鎖成功
讀共享, 並行處理
線程A加寫鎖成功, 又來了三個線程, 做讀操作, 三個線程阻塞
寫讀占, 串行處理
線程A加讀鎖成功, 又來了B線程加寫鎖阻塞, 在B之后來了C線程加讀鎖阻塞
讀寫不能同時進行
寫的優先級高
(4) 讀寫鎖場景練習
線程A加寫鎖成功, 線程B請求讀鎖:
線程B阻塞
線程A持有讀鎖, 線程B請求寫鎖:
線程B阻塞
線程A擁有讀鎖, 線程B請求讀鎖
線程B加鎖成功
線程A持有讀鎖, 然后線程B請求寫鎖, 然后線程B請求讀鎖
B阻塞, C阻塞 --> 寫的優先級高
A解鎖, B線程加寫鎖成功, C繼續阻塞
B解鎖, C加讀鎖成功
線程A持有寫鎖, 然后線程B請求讀鎖, 然后線程C請求寫鎖
B, C阻塞
A解鎖, C加寫鎖, B阻塞
C解鎖, B加鎖成功
(5) 讀寫鎖使用場景
互斥鎖--> 讀寫串行
讀寫鎖--> 讀: 並行; 寫: 串行
程序中讀操作大於寫操作
(6) 主要處理函數
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); 初始化讀寫鎖
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);銷毀讀寫鎖
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);加讀鎖
阻塞: 之前對這把鎖加的寫鎖的操作
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);嘗試加讀鎖
加鎖成功: 0; 加鎖失敗: 錯誤號
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);加寫鎖
阻塞: 上一次加寫鎖還沒有解鎖; 上一次加讀鎖沒解鎖
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);嘗試加寫鎖
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);解鎖
(7) 讀寫鎖和互斥鎖, 並不是任何時候都能阻塞線程
(8) 練習
3個線程不定時寫同一全局資源, 5個線程不定時讀同一全局資源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
int number = 0;
// 讀寫鎖
pthread_rwlock_t lock;
void *write_func(void *arg) {
while (1) {
pthread_rwlock_wrlock(&lock);
number++;
printf("+++++write: %lu, %d\n", pthread_self(), number);
pthread_rwlock_unlock(&lock);
sleep(1);
}
return NULL;
}
void *read_func(void *arg) {
while (1) {
pthread_rwlock_rdlock(&lock);
printf("======read: %lu, %d\n", pthread_self(), number);
pthread_rwlock_unlock(&lock);
sleep(1);
}
return NULL;
}
int main() {
int i;
pthread_t p[8];
// 初始化讀寫鎖
pthread_rwlock_init(&lock, NULL);
// 3個寫線程
for (i = 0; i < 3; i++) {
pthread_create(&p[i], NULL, write_func, NULL);
}
// 5個讀線程
for (i = 3; i < 8; i++) {
pthread_create(&p[i], NULL, read_func, NULL);
}
// 回收子線程
for (i = 0; i < 8; i++) {
pthread_join(p[i], NULL);
}
for (i = 0; i < 8; i++) {
pthread_rwlock_destroy(&lock);
}
return 0;
}
