Linux 锁机制(2)之读写锁 rwlock_t

1. 读写锁特性

读写锁的特性为:写独占,读共享;写锁优先级高。
对于读写锁,掌握了这12个字就足矣了。

2. 写独占,读共享;写锁优先级高 解析

  1. 读写锁是“写模式加锁”时, 解锁前,所有尝试对该锁进行加锁(不管是读锁还是写锁)的线程都会被阻塞;–> 写独占
  2. 读写锁是“读模式加锁”时, 如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞。–> 读共享
  3. 读写锁是“读模式加锁”时, 既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求,优先满足写模式锁。–> 写锁优先级高

3. 适用场景

读写锁非常适合于对数据结构读多写少的情况。

4. 读写锁API

4.1 Linux线程相关API

pthread_rwlock_init函数
pthread_rwlock_destroy函数
pthread_rwlock_rdlock函数
pthread_rwlock_wrlock函数
pthread_rwlock_tryrdlock函数
pthread_rwlock_trywrlock函数
pthread_rwlock_unlock函数

4.2 系统相关API

方法		描述
rwlock_init()	初始化指定的rwlock_t
read_lock()		获取指定的读锁
read_unlock()	释放指定的读锁
write_lock()	获得指定的写锁
write_unlock()	释放指定的写锁
write_trylock()	试图获得指定的写锁;如果写锁不可用,返回非0值

read_lock_irq()		禁止本地中断并获得指定读锁
read_unlock_irq()	释放指定的读锁并激活本地中断
read_lock_irqsave()	存储本地中断的当前状态,禁止本地中断并获得指定读锁
read_unlock_irqrestore()	释放指定的读锁并将本地中断恢复到指定前的状态

write_lock_irq()	禁止本地中断并获得指定写锁
write_unlock_irq()	释放指定的写锁并激活本地中断
write_lock_irqsave()存储本地中断的当前状态,禁止本地中断并获得指定写锁
write_unlock_irqrestore()	释放指定的写锁并将本地中断恢复到指定前的状态

5. 读写锁缺点及解决

读写锁的缺点(写独占时不可读)
RCU 是对读写锁的优化/替换,解决读写互斥问题(随时读,写互斥)

具体参考:
Linux RCU机制
https://blog.csdn.net/lqy971966/article/details/118993557

6. 代码例子

/* 2个线程不定时 "写" 全局资源,3个线程不定时 "读" 同一全局资源 */

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#define COUNT_OF_READ 3
#define COUNT_OF_WRITE 2

int g_iCounter;                          //全局资源
pthread_rwlock_t g_iRwLock;

void *th_write(void *arg)
{
	int iTmpCount = 0;
	int iTmpArg = (int)(int*)arg;

	while (1) {
		iTmpCount = g_iCounter;
		usleep(1000);

		pthread_rwlock_wrlock(&g_iRwLock);
		printf("=====write %d: %lu: g_iCounter=%d ++g_iCounter=%d\n", iTmpArg, pthread_self(), iTmpCount, ++g_iCounter);
		/* pthread_self 返回线程ID */
		pthread_rwlock_unlock(&g_iRwLock);

		usleep(5000);
	}
	return NULL;
}

void *th_read(void *arg)
{
	int iTmpArg = (int)(int*)arg;

	while (1) {
		pthread_rwlock_rdlock(&g_iRwLock);
		printf("-----read %d: %lu: %d\n", iTmpArg, pthread_self(), g_iCounter);
		pthread_rwlock_unlock(&g_iRwLock);

		usleep(900);
	}
	return NULL;
}

int main(void)
{
	int iCount = 0;
	pthread_t tid[COUNT_OF_WRITE + COUNT_OF_READ];

	pthread_rwlock_init(&g_iRwLock, NULL);

	for (iCount = 0; iCount < COUNT_OF_WRITE; iCount++)
		pthread_create(&tid[iCount], NULL, th_write, (void *)iCount);

	for (iCount = 0; iCount < COUNT_OF_READ; iCount++)
		pthread_create(&tid[iCount+3], NULL, th_read, (void *)iCount);

	for (iCount = 0; iCount < COUNT_OF_WRITE + COUNT_OF_READ; iCount++)
		pthread_join(tid[iCount], NULL);

	pthread_rwlock_destroy(&g_iRwLock);            //释放读写琐

	return 0;
}

结果:

root@localhost home]# gcc rwlock.c -lpthread                                        ^
[root@localhost home]# ./a.out > rrr
^C
[root@localhost home]# head -n 30 rrr 
-----read 0: 140041912997632: 0
-----read 1: 140041904604928: 0
-----read 2: 140041896212224: 0
=====write 0: 140041929783040: g_iCounter=0 ++g_iCounter=1
-----read 2: 140041896212224: 1
-----read 1: 140041904604928: 1
=====write 1: 140041921390336: g_iCounter=0 ++g_iCounter=2
-----read 0: 140041912997632: 2
-----read 1: 140041904604928: 2
-----read 2: 140041896212224: 2
-----read 0: 140041912997632: 2
-----read 2: 140041896212224: 2
-----read 1: 140041904604928: 2
-----read 0: 140041912997632: 2
-----read 1: 140041904604928: 2
-----read 2: 140041896212224: 2
-----read 0: 140041912997632: 2
-----read 2: 140041896212224: 2
-----read 1: 140041904604928: 2
-----read 0: 140041912997632: 2
=====write 0: 140041929783040: g_iCounter=2 ++g_iCounter=3
=====write 1: 140041921390336: g_iCounter=2 ++g_iCounter=4
-----read 2: 140041896212224: 4
-----read 1: 140041904604928: 4
-----read 0: 140041912997632: 4
-----read 2: 140041896212224: 4
-----read 1: 140041904604928: 4
-----read 0: 140041912997632: 4
-----read 1: 140041904604928: 4
-----read 0: 140041912997632: 4
[root@localhost home]# 

代码优化了一下 参考:
https://blog.csdn.net/yychuyu/article/details/84677883

参考:

1. https://cloud.tencent.com/developer/news/308874

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值