linux读写锁_共享内存读写锁

linux读写锁_共享内存读写锁一、读写锁是什么?读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的ps:读写锁本质上是一种自旋锁二、为什么需要读写锁?有时候,在多线程中,有一些公共数据修改的机会比较少,而读的机会却是非常多的,此公共数据的操作基本都是读,如果每次操作都给此段代码加锁,太浪费时间了而且也很浪费资源…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新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;
}

运行结果:
这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/169974.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 深度剖析LinkedHashSet「建议收藏」

    深度剖析LinkedHashSet「建议收藏」HashMap是一个利用数组存储key-value键值对的一个数据结构,为了有序的要求,然后我们引入了LinkedHashMap来满足我们对顺序的要求,再到后面我们学习了HashSet这种数据结构,利用的是HashMap的Key的唯一性来实现HashSet的去重的目的LinkedHashSet也HashSet一样也在内部使用了HashMap,因为LinkedHashSet要维持元素之间的顺序,所以它使用的实HashMap的有序版本,也就是LinkedHashMap

    2022年10月12日
    2
  • 精选30道Java笔试题解答

    精选30道Java笔试题解答都是一些非常非常基础的题,是我最近参加各大IT公司笔试后靠记忆记下来的,经过整理献给与我一样参加各大IT校园招聘的同学们,纯考Java基础功底,老手们就不用进来了,免得笑话我们这些未出校门的孩纸们,但

    2022年8月6日
    5
  • pycharm pyinstaller打包exe_pip安装第三方库失败

    pycharm pyinstaller打包exe_pip安装第三方库失败1.安装时打开AnacondaPrompt,然后cdD:\Anaconda3\pkgs打开路径,输入安装命令:pipinstallPyInstaller。最后输入piplist查看2.调出terminal终端,输入命令例如pyinstaller-F-wvipvideoplay2.py点击回车如图:输入指定命令后会在当前目录下生产dist文件夹,dist文件夹下为生成的exe文件参数说明:-F:将所有库文件打包成一个exe-w:隐藏黑色控制台窗口如果不加-F参数会生成很多文

    2022年8月27日
    6
  • uva-10194-排序

    uva-10194-排序

    2022年3月5日
    49
  • 关于Kotlin扩展函数与lambda的上下文

    关于Kotlin扩展函数与lambda的上下文

    2022年3月13日
    50
  • 根据/proc/partitions获取插入的U盘设备名称

    根据/proc/partitions获取插入的U盘设备名称1 在/proc/partitions中存放着U盘的设备名称,如sda,sdb2等,以sd开头。major主设备号,比如一个U盘有3个分区,主设备名为sda,major为8,分区的major也为8,minor则为分区号,sda1,sda2,minor值为1,2sda的minor为0,name即为设备名,连接/dev./设备名,就可以挂载到一个目录。blocks表示物理设备逻辑块

    2022年6月26日
    32

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号