linux线程通信和同步(读写锁)

一、读写锁


读写锁和互斥锁的区别

读写锁和互斥锁都可以解决多线程在访问共享资源竞争的问题,不同的是读写锁允许多个线程同时读某个共享变量,在同一时刻只允许一个线程对变量进行写操作,因此读写锁的效率要高于互斥锁。


读写锁是几把锁

读写锁其实是一把锁,但是这把锁拥有读和写两种属性;


读写锁的状态

读写锁存在三种状态:

  • 写加锁,此时其它任何试图获取读锁或写锁的线程都将被阻塞,这种属性称为写独占;
  • 读加锁,此时其它任何试图获取读锁的线程都可以加锁成功,这种属性被称为读共享;
  • 读加锁,此时如果既有线程试图获取读锁,又有线程试图获取写锁,那么系统会优先让线程获得写锁并阻塞获取读锁的线程,也可以简单理解为写锁的优先级高于读锁;

需要注意的问题

读写锁在使用时也应该注意线程优先级带来的影响,在实时调度属性的线程中,如果获取读锁的线程优先级高并且一直占用锁,会导致试图获取写锁的低优先级线程无法运行,反之也成立;


应用场景

读写锁非常适用于数据的读次数远高于写次数的场景,因为这样可以大大提高线程的执行效率;举个简单的例子,比如有100个线程同时需要读取变量x的值,它们每个线程执行完锁需要的时间是1ms.如果使用读写锁,这些线程的状态则为并行,即100个线程执行完只需要1ms。而如果使用互斥锁,这些线程的状态则为串行,这些线程执行完需要的时间大约为100ms。

相信很多人会问这样一个问题:既然读锁可以共享,那么我们只需要给写的线程加上一个互斥锁不就行了。对于读写频率比较低的场景这样似乎也不会产生什么问题,但是如果读写频率太高就会存在读和写同时访问内存的情况,这种情况产生的结果是不可预知的,而使用读写锁可以保证线程在写的时候不会产生读的动作,在读的时候不会产生写的动作,从而保证了数据安全。


适用范围

读写锁只适用于对变量、内存以及队列、链表等的操作,不适用于硬件接口,比如使用spi读写flash数据,对于硬件接口相关的访问只能使用互斥锁或者自旋锁。

读写锁常用函数

1.pthread_rwlock_init初始化读写锁

函数原型: int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
函数功能:初始化读写锁
函数参数:rwlock 读写锁句柄
          attr 读写锁参数,如果这个值为NULL,则使用系统默认的读写锁参数
返回值:成功返回0,失败返回对应的错误码

2.pthread_rwlock_rdlock和pthread_rwlock_tryrdlock获取读锁

函数原型:  int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
           int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

函数功能:这两个函数都可以获取读锁,不同的是pthread_rwlock_rdlock以阻塞的方式获取读锁,pthread_rwlock_tryrdlock以非阻塞的方式获取读锁
函数参数:rwlock 读写锁句柄
返回值:成功返回0,失败返回对应的错误码

3.pthread_rwlock_wrlock和pthread_rwlock_trywrlock 获取写锁

函数原型: int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
          int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
函数功能:这两个函数都可以获取写锁,不同的是pthread_rwlock_wrlock以阻塞的方式获取读锁,pthread_rwlock_trywrlock以非阻塞的方式获取读锁
函数参数:rwlock 读写锁句柄
返回值:成功返回0,失败返回对应的错误码

4.pthread_rwlock_timedrdlock和pthread_rwlock_timedwrlock以超时的方式获取读锁和写锁

函数原型: int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
           int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
函数功能:以超时的方式获取读锁和写锁

5.pthread_rwlock_unlock 解锁读写锁

函数原型:int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
函数功能:解锁读写锁

示例:

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

pthread_attr_t g_attr;
pthread_t tid1[11],tid2[11];
pthread_rwlock_t g_wr_lock;
unsigned int g_count = 0;

void set_thread_pri(pthread_t id,int prio)
{
	struct sched_param pri; 
	pri.sched_priority = prio;
	if(0 != pthread_setschedparam(id,SCHED_FIFO ,&pri))
		printf("thread shed policy set fail\r\n");
}
void *pthread1(void *param)
{
    int id = (int)param;
	//set_thread_pri(pthread_self(),15);
	sleep(1);
	pthread_detach(pthread_self());
	while(g_count<100)
	{
		pthread_rwlock_wrlock(&g_wr_lock);
		g_count++;
		printf("%d thread get write_lock,count = %d\r\n",id,g_count);
		pthread_rwlock_unlock(&g_wr_lock);
		sleep(1);
	}
}
void *pthread2(void *param)
{
	int id = (int)param;
	//set_thread_pri(pthread_self(),10);
	sleep(1);
	pthread_detach(pthread_self());
	while(g_count<100)
	{
		pthread_rwlock_rdlock(&g_wr_lock);
		printf("%d thread get read_lock,count = %d\r\n",id,g_count);
		pthread_rwlock_unlock(&g_wr_lock);
		sleep(1);
	}
}

int main()
{
	int ret = -1;
	int i = 0;
	unsigned int stacksize = 0;
	struct sched_param pri; 
	int detachstate;
	void* stackaddr;
	
	//设置进程调度方式和优先级,所有线程的默认调度方式和优先级同进程
	//pri.sched_priority = 11;
	//if(0 != sched_setscheduler(getpid(),SCHED_FIFO,&pri))
	//{
	//	printf("process shed policy set fail\r\n");
	//}
	//初始化读写锁
	ret = pthread_rwlock_init(&g_wr_lock,NULL);
	if(0 != ret)
	{
		printf("wr lock init error\r\n");
		return -1;
	}
	for(i=0;i<10;i++)
	    pthread_create(&tid1[i],NULL,pthread1,(void*)i);//线程attr为NULL表示使用系统默认属性
	for(i=0;i<20;i++)
	    pthread_create(&tid2[i],NULL,pthread2,(void*)i);
	//设置线程调度策略
    while(1)
	{
		sleep(100);
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值