当前位置: 首页 > news >正文

Linux互斥量读写锁

一、互斥量

1.临界资源

        同一时刻只允许一个进程/线程访问的共享资源(比如文件、外设打印机)

2.临界区

        访问临界资源的代码

3.互斥机制

        mutex互斥锁,用来避免临界资源的访问冲突,访问临界资源前申请互斥锁,访问完释放锁

 形象点的说法 好比有一个公共卫生间,进去使用的人会给门上锁,使用完会开锁

4.创建互斥锁 

/*动态创建*/
pthread_mutex_t mutex
pthread_mutex_t_init(pthread_mutex_t *mutex,互斥锁属性 给NULL默认即可)
/*静态创建*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

5.销毁互斥锁

pthread_mutex_destory(pthread_mutex_t *mutex)

Linux中,互斥锁不占任何资源,所以销毁锁不是必须的,可利用其返回值查询锁状态,锁定时返回EBUSY

6.申请互斥锁(P操作) 

pthread_mutex_lock(pthread_mutex_t *mutex) //无锁时阻塞等待
pthread_mutex_trylock(pthread_mutex_t *mutex) //无锁返回EBUSY

7.释放互斥锁(V操作)

pthread_mutex_unlock(pthread_mutex_t *mutex) 
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;FILE *fp;
void *func2(void *arg){pthread_detach(pthread_self());printf("This func2 thread\n");char str[]="I write func2 line\n";char c;int i=0;while(1){pthread_mutex_lock(&mutex);while(i<strlen(str)){c = str[i];fputc(c,fp);usleep(1);i++;}pthread_mutex_unlock(&mutex);i=0;usleep(1);}pthread_exit("func2 exit");}void *func(void *arg){pthread_detach(pthread_self());printf("This is func1 thread\n");char str[]="You read func1 thread\n";char c;int i=0;while(1){pthread_mutex_lock(&mutex);while(i<strlen(str)){c = str[i];fputc(c,fp);i++;usleep(1);}pthread_mutex_unlock(&mutex);i=0;usleep(1);}pthread_exit("func1 exit");
}int main(){pthread_t tid,tid2;void *retv;int i;fp = fopen("1.txt","a+");if(fp==NULL){perror("fopen");return 0;}pthread_create(&tid,NULL,func,NULL);pthread_create(&tid2,NULL,func2,NULL);while(1){    sleep(1);} }

二、读写锁

与互斥锁的区别是:

  • 互斥锁对所有线程一视同仁,同一时刻只允许一个线程访问临界资源

  • 读写锁区分读者和写者同一时刻只允许一个写者访问临界资源,而读者允许多个同时访问,更具体地:

    • 写锁状态时,其他写锁、读锁都被阻塞;

    • 读锁状态时,读锁不阻塞,写锁阻塞,但在写锁阻塞之后申请的读锁要阻塞等待写锁(否则重要的内容一直写不进去)

pthread_rwlock_t rwlock //定义读写锁
/*申请写锁*/
pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
/*申请读锁*/
pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
/*释放锁*/
pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
/*销毁读写锁*/
pthread_rwlock_destory(pthread_rwlock_t *rwlock)
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>pthread_rwlock_t rwlock;FILE *fp;
void * read_func(void *arg){pthread_detach(pthread_self());printf("read thread\n");char buf[32]={0};while(1){//rewind(fp);pthread_rwlock_rdlock(&rwlock);while(fgets(buf,32,fp)!=NULL){printf("%d,rd=%s\n",(int)arg,buf);usleep(1000);}pthread_rwlock_unlock(&rwlock);sleep(1);}}void *func2(void *arg){pthread_detach(pthread_self());printf("This func2 thread\n");char str[]="I write func2 line\n";char c;int i=0;while(1){pthread_rwlock_wrlock(&rwlock);while(i<strlen(str)){c = str[i];fputc(c,fp);usleep(1);i++;}pthread_rwlock_unlock(&rwlock);i=0;usleep(1);}pthread_exit("func2 exit");}void *func(void *arg){pthread_detach(pthread_self());printf("This is func1 thread\n");char str[]="You read func1 thread\n";char c;int i=0;while(1){pthread_rwlock_wrlock(&rwlock);while(i<strlen(str)){c = str[i];fputc(c,fp);i++;usleep(1);}pthread_rwlock_unlock(&rwlock);i=0;usleep(1);}pthread_exit("func1 exit");
}int main(){pthread_t tid1,tid2,tid3,tid4;void *retv;int i;fp = fopen("1.txt","a+");if(fp==NULL){perror("fopen");return 0;}pthread_rwlock_init(&rwlock,NULL);pthread_create(&tid1,NULL,read_func,1);pthread_create(&tid2,NULL,read_func,2);pthread_create(&tid3,NULL,func,NULL);pthread_create(&tid4,NULL,func2,NULL);while(1){    sleep(1);} }

死锁的避免

概念:有两把锁以上时,多个线程各自申请到锁时,紧接着申请其他线程占用着的锁,它们都会处于阻塞等待,形成【死锁】

避免方法:

  • 锁越少越好,一把锁无需考虑死锁问题

  • 调整锁的顺序

    • 一种笨策略是,某个线程如果想要申请多个锁,那么可以等其释放完,其他线程再申请

    • 另一种笨策略是,各个线程按同样的顺序申请多个锁

 

http://www.lryc.cn/news/495557.html

相关文章:

  • 网络安全之IP伪造
  • ARM CCA机密计算安全模型之硬件强制安全
  • 【论文笔记】A Token-level Contrastive Framework for Sign Language Translation
  • C#窗体简单登录
  • 基于ZYNQ-7000系列的FPGA学习笔记3——开发环境搭建点亮一个LED
  • 队列-链式描述(C++)
  • Kali Linux使用Netdiscover工具的详细教程
  • arkTS:使用ArkUI实现用户信息的持久化管理与自动填充(PersistentStorage)
  • IntelliJ+SpringBoot项目实战(二十)--基于SpringSecurity实现Oauth2服务端和客户端
  • 如何实现剪裁功能
  • LeetCode 动态规划 爬楼梯
  • Java 工厂模式:深度解析与应用指南
  • HTML5系列(5)-- SVG 集成详解
  • 深度学习常见数据集处理方法
  • 1180 - 【入门】数字出现次数
  • C++20: 像Python一样split字符串
  • Unity3D UI 嵌套滚动视图
  • 你还没有将 Siri 接入GPT对话功能吗?
  • _C#_串口助手_字符串拼接缺失问题(未知原理)
  • 浅析大数据时代下的网络安全
  • Mysql数据库基础篇笔记
  • rabbitmq原理及命令
  • React进阶面试题(四)
  • 24/12/1 算法笔记<强化学习> 创建Maze交互
  • Linux驱动开发(10):I2C子系统–mpu6050驱动实验
  • 《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》
  • 如何将多个JS文件打包成一个JS文件?
  • 100个python经典面试题详解(新版)
  • C#初阶概念理解
  • node.js基础学习-url模块-url地址处理(二)