大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
一、读写锁是什么?
读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的
ps:读写锁本质上是一种自旋锁
二、为什么需要读写锁?
有时候,在多线程中,有一些公共数据修改的机会比较少,而读的机会却是非常多的,此公共数据的操作基本都是读,如果每次操作都给此段代码加锁,太浪费时间了而且也很浪费资源,降低程序的效率,因为读操作不会修改数据,只是做一些查询,所以在读的时候不用给此段代码加锁,可以共享的访问,只有涉及到写的时候,互斥的访问就好了
三、读写锁的行为
读写之间是互斥的—–>读的时候写阻塞,写的时候读阻塞,而且读和写在竞争锁的时候,写会优先得到锁
四、自旋锁&挂起等待是锁?
1.自旋锁
自旋锁是在发生获取不到锁的时候,会直接等待,不会被CPU直接调度走,而是会一直等到获取到锁,因为此锁是一直的在等待,所以不会有调度的开销,故此锁的效率比挂起等待锁的效率高,但是此锁会因不停的查看锁的释放情况,故会浪费更多的CPU资源
2.挂起等待锁
挂起等待锁是当某线程在执行临界区的代码时,那其他线程只能挂起等待,此时这些线程会被CPU调度走,等到锁释放(即就是临界区的代码被之前的那个线程已经执行完毕),而且被CPU调度的线程只有被调度回来才可以执行临界区的代码
挂起等待锁是在发生获取不到锁的时候,他会被CPU调度走,去做别的事,但是会时不时的去查看锁有没有被释放
ps:线程想执行临界区的代码的条件:
(1)锁释放;
(2)被CPU调度回来
3.自旋锁的优缺点
优点:效率高,避免了线程之间调度的开销
缺点:浪费CPU资源
4.挂起等待锁的优缺点
优点:不会浪费CPU的资源,比较灵活
缺点:效率不高,很可能会使临界区的代码不被任何线程执行,因为可能会是线程被
CPU调度走了但是却没有被调度回来
五、读写锁是怎么实现?
1.一种交易场所(存放数据的地方):可以是变量、链表、数组或其他数据结构
2.两种角色:读操作和写操作
3.三种关系:(1)读和读之间没有关系
(2) 写和写之间是互斥关系
(3)读和写之间是同步互斥关系
ps:同步---->读和写在同时竞争锁的时候,写会优先的得到锁
互斥---->读的时候写阻塞,写的时候读阻塞
4.相关函数
(1)pthread_rwlock_init()—->初始化函数
功能:初始化读写锁
头文件:#include<pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthred_rwlockattr_t *restrict attr);
参数说明:
rwlock:是要进行初始化的
attr:是rwlock的属性
ps:此参数一般不关注,可设为NULL
(2)pthread_rwlock_destroy—->销毁函数
功能:销毁初始化的锁
头文件:#include<pthread.h>
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
参数说明:
rwlock:是需要进行销毁的锁
(3)加锁和解锁
在进行读操作的时候加的锁:
pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
在进行写操作的时候加的锁:
pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
对读/写统一进行解锁:
pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
六、代码实现读写锁
#include<stdio.h>
#include<unistd.h>
#include<malloc.h>
#include<stdlib.h>
#include<pthread.h>
pthread_rwlock_t rwlock;//声明读写锁
int count;
//写者线程的入口函数
void*route_write(void*arg)
{
int i=*(int*)arg;//i是写者线程的编号
free(arg);
while(1){
int t=count;
//加锁
pthread_rwlock_wrlock(&rwlock);
printf("route_write:%d,%#x,count=%d,++count=%d\n",i,\
pthread_self(),t,++count);
//解锁
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
//读者线程的入口函数
void*route_read(void*arg)
{
int i=*(int*)arg;//i是读者线程的编号
free(arg);
while(1){
//加锁
pthread_rwlock_rdlock(&rwlock);
printf("route_read:%d,%#x,count=%d\n",i,pthread_self(),count);
//解锁
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
int main()
{
int i=0;
//初始化读写锁
pthread_rwlock_init(&rwlock,NULL);
pthread_t tid[8];
//创建3个写者线程
for(i=0;i<3;i++){
int*p=(int*)malloc(sizeof(int));
*p=i;
pthread_create(&tid[i],NULL,route_write,(void*)p);
}
//创建3个读者线程
for(i=0;i<5;i++){
int*p=(int*)malloc(sizeof(int));
*p=i;
pthread_create(&tid[i+3],NULL,route_read,(void*)p);
}
//主线程等待新创建的线程
for(i=0;i<8;i++)
pthread_join(tid[i],NULL);
//销毁读写锁
pthread_rwlock_destroy(&rwlock);
return 0;
}
运行结果:
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/169974.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...