一、读写锁
读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。
1.特性
- 锁只有一把,“读锁”、“写锁”是加锁的两种方式。“读锁”是读模式下加锁状态,“写锁”是写模式下加锁状态。
- 一个读写锁同时只能有一个写者,可以有多个读者,但读者和写者不能同时访问(读共享,写独占)。
- 写锁优先级高。
2.具体情景下读者写者优先级分析
现在有两个写者w1,w2;三个读者r1,r2,r3;
- [ 1 ]r1,r2,r3同时访问,均能获取锁并读取数据;
- [ 2 ]r1,w1同时竞争,w1能获取锁,进行写操作,r1阻塞;
- [ 3 ]r1加锁成功,w1,r2,w2同时请求访问,则三者均会阻塞,在r1释放锁时,w1,w2会竞争抢夺,r2优先级排在最后;
- [ 4 ]r1加锁成功,r2,r3同时请求访问,则均能加锁成功,进行读操作;
- [ 5 ]w1加锁成功,则不论后续是谁请求访问,均会阻塞。
3.读写锁相关操作
pthread_rwlock_t rwlock; //定义
pthread_rwlock_init(&rwlock, NULL); //初始化
pthread_rwlock_rdlock(&rwlock); //读模式加锁,失败时阻塞
pthread_rwlock_tryrdlock(&rwlock); //读模式尝试加锁,失败时立即返回
pthread_rwlock_wrlock(&rwlock); //写模式加锁,失败时阻塞
pthread_rwlock_wrlock(&rwlock); //写模式尝试加锁,失败时立即返回
pthread_rwlock_unlock(&rwlock); //解锁
pthread_rwlock_destroy(&rwlock); //销毁锁
二、Demo
3个线程不定时 “写” 全局资源,5个线程不定时 “读” 同一全局资源
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int counter; //全局资源
pthread_rwlock_t rwlock;
void *th_write(void *arg)
{
int t;
int i = (int)arg;
while (1) {
t = counter; // 保存写之前的值
usleep(1000);
pthread_rwlock_wrlock(&rwlock);
printf("=======write %d: %lu: counter=%d ++counter=%d\n", i, pthread_self(), t, ++counter);
pthread_rwlock_unlock(&rwlock);
usleep(9000); // 给 r 锁提供机会
}
return NULL;
}
void *th_read(void *arg)
{
int i = (int)arg;
while (1) {
pthread_rwlock_rdlock(&rwlock);
printf("----------------------------read %d: %lu: %d\n", i, pthread_self(), counter);
pthread_rwlock_unlock(&rwlock);
usleep(2000); // 给写锁提供机会
}
return NULL;
}
int main(void)
{
int i;
pthread_t tid[8];
pthread_rwlock_init(&rwlock, NULL);
for (i = 0; i < 3; i++)//创建3个写者线程
pthread_create(&tid[i], NULL, th_write, (void *)i);
for (i = 0; i < 5; i++)//创建5个读者线程
pthread_create(&tid[i+3], NULL, th_read, (void *)i);
for (i = 0; i < 8; i++)//回收线程资源
pthread_join(tid[i], NULL);
pthread_rwlock_destroy(&rwlock); //释放读写琐
return 0;
}