线程的同步和互斥学习笔记

目录

互斥锁的概念和使用 

线程通信-互斥

 互斥锁的创建和销毁

 申请锁-pthread_mutex_lock

 释放锁-pthread_mutex_unlock

读写锁的概念和使用

死锁的避免


互斥锁的概念和使用 

线程通信-互斥

临界资源

  • 一次只允许一个任务(进程、线程)访问的共享资源

概念:

        不能同时访问的资源,比如写文件,只能由一个线程写,同时写会写乱。

        比如外设打印机,打印的时候只能由一个程序使用。

        外设基本上都是不能共享的资源。

        生活中比如卫生间,同一时间只能由一个人使用。

临界区

  • 访问临界资源的代码

互斥机制

  • mutex互斥锁,任务访问临界资源前申请锁,访问完后释放锁

 互斥锁的创建和销毁

两种方法创建互斥锁,静态方式和动态方式: 

动态方式: 

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
  • 成功时返回0,失败时返回错误码
  • mutex指向要初始化的互斥锁对象
  • attr互斥锁属性,NULL表示缺省属性
  • man函数出现No manual entry for pthread_mutex_xxx解决方法:apt-get install manpages-posix-dev

 静态方式:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

 锁的销毁:

int pthread_mutex_destory(pthread_mutex_t *mutex)

在linux中,互斥锁并不占用任何资源,因此LinuxThreads中的pthread_mutex_destory()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。

 申请锁-pthread_mutex_lock

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
  • 成功时返回0,失败时返回错误码
  • mutex指向要初始化的互斥锁对象
  • pthread_mutex_lock如果无法获得锁,任务阻塞
  • pthread_mutex_trylock如果无法获得锁,返回EBUSY而不是挂起等待

 释放锁-pthread_mutex_unlock

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 成功时返回0,失败时返回错误码
  • mutex指向要初始化的互斥锁对象

 示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
FILE *fp;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  //多个文件需要多个锁
void *func1(void *arg)
{pthread_detach(pthread_self());printf("This is child thread1\n");char str[] = "I write func1 line\n";char c;int i = 0;//pthread_mutex_t mutex1;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("func1 exit");
}
void *func2(void *arg)
{pthread_detach(pthread_self());printf("This is child thread2\n");char str[] = "You read func1 thread\n";char c;int i = 0;//pthread_mutex_t mutex2;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");
}
int main()
{ pthread_t tid1,tid2;void *retv;int i;   fp = fopen("1.txt","a+");if(fp == NULL){perror("fopen");return 0;}pthread_create(&tid1,NULL,func1,NULL);pthread_create(&tid2,NULL,func2,NULL);while(1){sleep(1);}
}

运行结果:

读写锁的概念和使用

 必要性:提高线程执行效率

特性:

  • 写者:写者使用写锁,如果当前没有读者,也没有其他写者,写者立即获得写锁;否则写者将等待,直到没有读者和写者。
  • 读者:读者使用读锁,如果当前没有写者,读者立即获得读锁;否则读者等待,直到没有写者。

 注意:

  • 同一时刻只有一个线程可以获得写锁,同一时刻可以有多个线程获得读锁
  • 读写锁出于写锁状态时,所有试图对读写锁加锁的线程,不管是读者试图加读锁,还是写者试图加写锁,都会被阻塞。
  • 读写锁处于读锁状态时,有写者试图加写锁时,之后的其他线程的读锁请求会被阻塞,以避免写者长时间的不写锁
  •  初始化一个读写锁        pthread_rwlock_init
  • 读锁定读写锁                pthread_rwlock_rdlock
  • 非阻塞读锁定                pthread_rwlock_tryrdlock
  • 写锁定读写锁                pthread_rwlock_wrlock
  • 非阻塞写锁定                pthread_rwlock_trywrlock
  • 解锁读写锁                    pthread_rwlock_unlock
  • 释放读写锁                    pthread_rwlock_destroy

 示例代码:

#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);} }

死锁的避免

  • 锁越少越好,最好使用一把锁
  • 调整好锁的顺序
  • 使锁进行错位

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
FILE *fp;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  //多个文件需要多个锁
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;  //多个文件需要多个锁void *func1(void *arg)
{pthread_detach(pthread_self());printf("This is child thread1\n");char str[] = "I write func1 line\n";char c;int i = 0;//pthread_mutex_t mutex1;while (1){pthread_mutex_lock(&mutex2);printf("%d,I get lock2\n",(int)arg);sleep(1);pthread_mutex_lock(&mutex);printf("%d,I get 2 locks\n",(int)arg);pthread_mutex_unlock(&mutex);pthread_mutex_unlock(&mutex2);sleep(10);}pthread_exit("func1 exit");
}
void *func2(void *arg)
{pthread_detach(pthread_self());printf("This is child thread2\n");char str[] = "You read func1 thread\n";char c;int i = 0;//pthread_mutex_t mutex2;while (1){pthread_mutex_lock(&mutex);printf("%d,I get lock1\n",(int)arg);sleep(1);pthread_mutex_lock(&mutex2);printf("%d,I get 2 locks\n",(int)arg);pthread_mutex_unlock(&mutex2);pthread_mutex_unlock(&mutex);usleep(10);}pthread_exit("func2 exit");
}
int main()
{ pthread_t tid1,tid2;void *retv;int i;   fp = fopen("1.txt","a+");if(fp == NULL){perror("fopen");return 0;}pthread_create(&tid1,NULL,func1,1);sleep(5);pthread_create(&tid2,NULL,func2,2);while(1){sleep(1);}
}

 运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643434.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑有网,浏览器连不上网,其他应用却能用

当我们访问浏览器的时候显示&#xff0c;你尚未链接&#xff0c;代理服务器可能有问题&#xff0c;或地址不正确的时候.可你的wifi任然是连接的&#xff0c;但是只有浏览器用不了&#xff0c;微信和其他程序都可以正常连接&#xff0c;这是为什么呢&#xff1f; 绝大多数是因为…

K8S的HPA

horiztal Pod Autoscaling&#xff1a;pod的水平自动伸缩&#xff0c;这是k8s自带的模块&#xff0c;它是根据Pod占用cpu比率到达一定的阀值&#xff0c;会触发伸缩机制 Replication controller 副本控制器&#xff1a;控制pod的副本数 Deployment controller 节点控制器&…

云原生网关哪家强:Sealos 网关血泪史

作者&#xff1a;Sealos 创始人&#xff0c;环界云计算 CEO 方海涛 Sealos 公有云 &#xff08;https://cloud.sealos.io&#xff09; 几乎打爆了市面上所有主流的开源网关&#xff0c;本文可以给大家很好的避坑&#xff0c;在网关选型方面做一些参考。 Sealos Cloud 的复杂场…

jenkins安装配置,使用Docker发布maven项目全过程记录(1)

使用的CentOS8 系统&#xff0c;其它Linux系统类似 1、jenkins安装 1.1、配置JAVA环境 使用的服务器环境中&#xff0c;安装了Java1.8与Java17&#xff0c;当前jenkins的最低java版本要求java11。系统默认使用的是java1.8&#xff0c;因此需要切换环境。 alternatives --co…

Qt采集本地摄像头推流成rtsp/rtmp(可网页播放/支持嵌入式linux)

一、功能特点 支持各种本地视频文件和网络视频文件。支持各种网络视频流&#xff0c;网络摄像头&#xff0c;协议包括rtsp、rtmp、http。支持将本地摄像头设备推流&#xff0c;可指定分辨率和帧率等。支持将本地桌面推流&#xff0c;可指定屏幕区域和帧率等。自动启动流媒体服…

flink-java使用介绍,flink,java,DataStream API,DataSet API,ETL

1、环境准备 文档&#xff1a;https://nightlies.apache.org/flink/flink-docs-release-1.17/zh/ 仓库&#xff1a;https://github.com/apache/flink 下载&#xff1a;https://flink.apache.org/zh/downloads/ 下载指定版本&#xff1a;https://archive.apache.org/dist/flink…

Spring复习-问题回答

1.什么是 spring&#xff0c;你对 spring 的理解? Spring是一个轻量级&#xff0c;非侵入式的&#xff08;不使用框架特定的类&#xff0c;感受不到框架&#xff09;IOC和AOP一站式的java后端开发框架&#xff0c;简化企业开发。 2.spring 的优缺点 优点&#xff1a; Spr…

STL第二讲

第二讲 视频标准库源码版本&#xff1a;gnu c 2.9.1/4.9/Visual C OOP vs GP GP是将datas与methods分开&#xff0c;OOP相反&#xff1b; 为什么list不能使用全局的sort&#xff1f; 因为sort源代码&#xff1a; *(first (last - first)/2) // 此迭代器只能是随机访问迭代…

使用 Python 数据写入 Excel 工作表

在数据处理和报告生成等工作中&#xff0c;Excel 表格是一种常见且广泛使用的工具。然而&#xff0c;手动将大量数据输入到 Excel 表格中既费时又容易出错。为了提高效率并减少错误&#xff0c;使用 Python 编程语言来自动化数据写入 Excel 表格是一个明智的选择。Python 作为一…

【nginx实战】nginx正向代理、反向代理、由反向代理实现的负载均衡、故障转移详解

文章目录 一. 正向代理与反向代理的概念二. Nginx服务器的正向代理服务1. Nginx服务器正向代理服务的配置的3个指令1.1. resolver指令1.2. resolver_timeout指令1.3. proxy_pass指令 2. Nginx服务器正向代理服务的使用 三. Nginx服务器的反向代理服务1. 反向代理的基本指令1.1.…

docker使用笔记

最近在使用docker配置小米cyberdog2的环境&#xff0c;记录一下常用的命令&#xff0c;以备今后查阅。 0. 基本概念 Dockerfile&#xff1a;环境的配置信息&#xff0c;里面描述了你想要搭建的环境的信息。 Image(镜像)&#xff1a;类比我们装虚拟机/操作系统时需要的系统镜像…

git本地分支的合并/切换分支时遇到的问题

目录 第一章、本地分支的切换测试1.1&#xff09;切换之前的master分支下文件内容1.2&#xff09;切换到develop分支后修改文件1.3&#xff09;切回master分支出现报错&#xff1a; 第二章、解决方式2.1&#xff09;方式1&#xff1a;commit提交修改2.2&#xff09;方式2&#…

设计模式—行为型模式之命令模式

设计模式—行为型模式之命令模式 命令&#xff08;Command&#xff09;模式&#xff1a;将一个请求封装为一个对象&#xff0c;使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通&#xff0c;这样方便将命令对象进行储存、传递、调用、增加与管理。 …

告别无法访问的Github

告别无法访问的Github 最近在使用github的时候又登不上去了&#xff0c;挂着VPN都没用 但是自己很多项目都存在github&#xff0c;登不上去那不得损失很大 所以一行必须整点儿特殊手段来访问&#xff0c;顺便分享一下 1.加速器 网上很多解决方案都是在分享各种加速器来登陆…

有效的括号[简单]

>优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串s&#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 【1】左括号必须用相同类型的右括号…

春招冲刺第二天——SQL学习

春招冲刺第二天 前言 MySQL学习&#xff1a;哔哩哔哩参考视频&#xff1a; 【中字】SQL进阶教程 | 史上最易懂SQL教程&#xff01;10小时零基础成长SQL大师 第一章 Mysql安装 视频前三节有教程&#xff0c;或自行查阅&#xff0c;不做赘述 课程资料和数据库数据的网盘&…

第八篇 交叉编译华为云Iot SDK到Orangepi3B

本篇主要内容&#xff1a; 一、交叉编译华为云Iot SDK依赖1.宿主机安装交叉编译工具链&#xff08;1&#xff09;选择下载交叉编译工具链&#xff08;2&#xff09;解压、添加环境变量、重启2.交叉编译依赖库&#xff08;0&#xff09; 准备工作&#xff08;1&#xff09; 交叉…

【多商户开源-BSD- Fecmall 电商平台】

关于Fecmall Fecmall 关于&#xff0c;Fecmall介绍 Fecbbc开源BSD多商户系统&#xff0c;真正开源&#xff0c;商用免费授权的多商户系统 Fecmall系统简介&#xff1a; 全称为Fancy ECommerce Shop&#xff0c; 着重于电商架构的研发优化&#xff0c;全新定义商城的架构体系&…

在Spring Boot中使用ZXing开源库生成带有Logo的二维码

在上一篇文章的基础上&#xff0c;我们将进一步扩展功能&#xff0c;实现在生成的二维码中嵌入Logo图片。这样的二维码更具个性化和识别度。让我们逐步完成这个功能。 第一步&#xff1a;引入Logo图片 首先&#xff0c;准备一张用作Logo的图片&#xff0c;并确保它的大小适中…

HIS项目介绍、项目环境准备、版本控制介绍、Git基础、Git指针、Git分支、Git标签

案例1&#xff1a;项目环境准备 环境准备说明&#xff1a; 本阶段共使用虚拟机6台&#xff0c;操作系统使用RockyLinux8.6 环境准备要求&#xff1a; 最小化安装即可配置好主机名和IP地址搭建好yum源关闭防火墙和SELinux!!! 项目主机列表 主机名IP地址规格角色服务Progra…