IO进程线程(九)线程的同步 进程间通信

文章目录

  • 一、 线程的同步
    • (一)无名信号量sem
      • 1. 定义和初始化
      • 2.获取信号量
      • 3.释放信号量
      • 4. 销毁
      • 5. 使用示例
    • (二)条件变量
      • 1. 定义和初始化
      • 2. 获取条件变量
      • 3. 释放条件变量
      • 4. 销毁条件变量
  • 二、进程间通信
    • (一)无名管道
      • 1.概念
      • 2. 定义
      • 3. 特点
    • (二)有名管道
      • 1. 原理
      • 2. 定义
      • 3. 特点
    • (三)信号通信
      • 1. 概念
      • 2. 定义

一、 线程的同步

线程同步:提前已经知道了线程应该有的执行的顺序,控制线程按指定的顺序执行

互斥锁无法保证线程执行的顺序,一个线程解锁后无法保证是另一个线程上锁,有可能仍是原来刚解锁的线程又再次上锁

无名信号量是荷兰计算器科学家发明的,PV操作的PV来自荷兰语。

(一)无名信号量sem

1. 定义和初始化

#include <semaphore.h>定义无名信号量sem_t  sem;
初始化无名信号量int sem_init(sem_t *sem, int pshared, unsigned int value);功能:初始化无名信号量参数:sem:无名信号量指针pshared:0:两个线程间同步非0:两个进程间同步value:信号量的初始值如果是1表示可以获取信号量如果是0表示不可以获取信号量返回值:成功 0失败 -1 重置错误码 

2.获取信号量

获取信号量(P操作)int sem_wait(sem_t *sem);功能:获取信号量 (将信号量的值-1)如果信号量的值已经是0了,则sem_wait会阻塞,等到能执行减1操作为止参数:sem:无名信号量指针返回值:成功 0失败 不会改变信号量的值 返回 -1 重置错误码 

3.释放信号量

释放信号量(V操作)int sem_post(sem_t *sem);功能:释放信号量(将信号量的值+1)参数:sem:无名信号量指针返回值:成功 0失败 不会改变信号量的值 返回 -1 重置错误码 

4. 销毁

销毁无名信号量int sem_destroy(sem_t *sem);功能:销毁无名信号量参数:sem:无名信号量指针返回值:成功 0
  • 注:
  • 无名信号量不允许减到小于1,当等于0时,sem_wait会阻塞等待;
  • 但是无名信号量允许加到大于1

5. 使用示例

现有三个线程,其功能分别为打印A、打印B、打印C,使用无名信号量使其按照ABC的顺序打印。

#include <my_head.h>sem_t sem1;
sem_t sem2;
sem_t sem3;//A线程
void *task_func_1(void *arg){while(1){sem_wait(&sem1);sleep(1);printf("A ");fflush(stdout);sem_post(&sem2);}
}//B线程
void *task_func_2(void *arg){while(1){sem_wait(&sem2);sleep(1);printf("B ");fflush(stdout);sem_post(&sem3);}
}
//C线程
void *task_func_3(void *arg){while(1){sem_wait(&sem3);sleep(1);printf("C ");fflush(stdout);sem_post(&sem1);}
}int main(int argc, const char *argv[])
{//初始化无名信号量sem_init(&sem1, 0, 1);sem_init(&sem2, 0, 0);sem_init(&sem3, 0, 0);pthread_t tid1 = 0, tid2 = 0, tid3=0;int ret = 0;if(0 != (ret = pthread_create(&tid1, NULL, task_func_1, NULL))){printf("pthread_create error : %s\n", strerror(ret));exit(-1);}if(0 != (ret = pthread_create(&tid2, NULL, task_func_2, NULL))){printf("pthread_create error : %s\n", strerror(ret));exit(-1);}if(0 != (ret = pthread_create(&tid3, NULL, task_func_3, NULL))){printf("pthread_create error : %s\n", strerror(ret));exit(-1);}pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);//销毁无名信号量sem_destroy(&sem1);sem_destroy(&sem2);sem_destroy(&sem3);return 0;
}

(二)条件变量

无名信号量适合线程数比较少的线程中实现微观的同步过程,
条件变量更适用于大量线程实现同步

1. 定义和初始化

#include <pthread.h>pthread_cond_t cond;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//静态初始化
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
功能:动态初始化条件变量
参数:cond:条件变量指针cond_attr:条件变量的属性 NULL 表示使用默认属性
返回值:成功 0  失败 错误码

2. 获取条件变量

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
功能:获取条件变量
参数:cond:条件变量指针mutex:互斥锁指针
返回值:成功 0  失败 错误码
使用流程:1.先获取到互斥锁(可以先完成一些任务初始化的工作)2.调用pthread_cond_wait2.1 将当前线程添加到队列中2.2 解锁2.3 在队列中休眠2.4 重新获取锁这时,如果等待的条件没有发生,会继续解锁、休眠如果等待的条件发生了,会将线程在队列中移除3.执行后续的任务4.解锁

3. 释放条件变量

int pthread_cond_signal(pthread_cond_t *cond);
功能:释放一个条件变量,唤醒一个等待条件的线程
参数:cond:条件变量指针
返回值:成功 0  失败 错误码int pthread_cond_broadcast(pthread_cond_t *cond);
功能:释放所有的资源,唤醒所有等待条件的线程
参数:cond:条件变量指针
返回值:成功 0  失败 错误码

4. 销毁条件变量

int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量
参数:cond:条件变量指针
返回值:成功 0  失败 错误码

二、进程间通信

进程间通信方式
1.传统进程间通信
无名管道
有名管道
信号通信
2.system V 版本引入了IPC进程间通信
消息队列
共享内存
信号灯集
socket套接字通信

(一)无名管道

1.概念

在使用fork函数创建子进程前打开的文件描述符,在fork之后,子进程会继承父进程打开的文件描述符。
在这里插入图片描述

无名管道是内核空间实现的机制,只能用于亲缘进程间通信,无名管道的大小是64K。

2. 定义

#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个管道 一个单向的数据通道 可用于进程间通信数组 pipefd 中会返回两个文件描述符,pipefd[0] 管道的读端  pipefd[1] 管道的写端写入管道的数据会被内核缓冲 直到被读走
参数:pipefd:保存管道的两个端点的文件描述符的数据
返回值:成功  0失败 -1 重置错误码

3. 特点

1.只能用于亲缘间进程的通信
2.无名管道数据半双工的通信的方式
单工 : A -------------->B
半双工 : 同一时刻 A----->B B------>A
全双工 : 同一时刻 A<---->B
3.无名管道的大小是64K
4.无名管道不能够使用lseek函数(调用会出错 返回 -1)
5.读写的特点
如果读端存在 写管道:有多少写多少,直到写满为止(64k)写阻塞,
直到管道中腾出新的4K空间,写操作解除阻塞
如果读端不存在 写管道,管道破裂(SIGPIPE)
如果写端存在 读管道:有多少读多少,没有数据的时候阻塞等待
如果写端不存在 读管道:有多少读多少,没有数据的时候立即返回(非阻塞)

(二)有名管道

1. 原理

有名管道会在文件系统中创建一个管道文件,只需要打开这个文件,进行读写操作即可。
有名管道是在文件系统中映射出一个管道文件名,管道文件本质是在内存上的,在硬盘上的只是一个标识。
在这里插入图片描述

2. 定义

mkfifo命令也可以创建管道文件
管道文件不能重名
在管道文件中写入内容,文件大小并不会增加,因为写入管道文件的内容保存在内存中,并非硬盘中

//也可以在终端上使用 mkfifo 命令创建管道文件
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:
参数:pathname:管道文件的路径和名字mode:权限   & ~umask  --》 最终权限
返回值:成功  0失败  -1 重置错误码

3. 特点

  1. 可以用于任意进程间的通信,不仅限亲缘进程
  2. 有名管道数据是半双工的通信方式
  3. 有名管道的大小是64K
  4. 有名管道不能够使用lseek函数(调用会失败 返回 -1)
  5. 读写的特点
    如果读端存在写管道:有多少写多少,直到写满为止(64k)写阻塞
    如果读端不存在写管道
    1.读端没有打开,写端在open的位置阻塞
    2.读端打开后关闭,管道破裂(SIGPIPE)
    如果写端存在读管道:有多少读多少,没有数据的时候阻塞等待
    如果写端不存在读管道
    1.写端没有打开,读端在open的位置阻塞
    2.写端打开后关闭,有多少读多少,没有数据的时候立即返回

(三)信号通信

1. 概念

信号是中断的一种软件模拟,中断是基于硬件的概念,信号是基于linux内核实现的。
用户可以给进程发信号,进程可以给进程发信号,linux内核也可以给进程发信号。
信号的处理方式有三种:默认DEF、忽略IGN、捕捉 caught
man 7 signal

信号查看:kill -l
在这里插入图片描述

2. 定义

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:注册信号和信号处理方式的关系
参数:signum:信号的编号handler:处理方式SIG_IGN  忽略SIG_DFL  默认也可以传一个函数  捕捉void sig_func(int signum){//自定义的逻辑}
返回值:成功  返回handler失败  SIG_ERR  重置错误码

signal函数只是注册了信号和处理方式的关系,并不会阻塞等待信号产生

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

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

相关文章

web-上传项目文件夹到Git远程仓库

Git初识 概念&#xff1a;一个免费开源&#xff0c;分布式的代码版本控制系统&#xff0c;帮助开发团队维护代码 作用&#xff1a;记录代码内容&#xff0c;切换代码版本&#xff0c;多人开发时高效合并代码内容 检验成功 打开bash终端&#xff08;git专用&#xff09;命令…

12. MySQL 日志

文章目录 【 1. 日志的基本原理 】【 2. 错误日志 Error Log 】2.1 启动和设置错误日志2.2 查看错误日志2.3 删除错误日志 【 3. 二进制日志 Binary Log 】3.1 启动和设置二进制日志3.2 查看二进制日志3.3 删除二进制文件删除所有二进制日志删除小于指定编号的二进制日志删除创…

【vue3+pinia+uniapp项目问题:使用pinia状态管理时store的数据更新,模板渲染视图不能实时更新】

在这里选择不同的学校后&#xff0c;发现store里面的数据打印出来能更新&#xff0c;但是使用store的数据打印出来并未实时更新且渲染在模板上&#xff0c;必须手动刷新视图才能更新。 原因是因为使用了解构赋值传入参数 解决方法 1.使用computed 现在视图能进行实时更新…

分享一个 .Net core Console 项目使用 SqlSugar 的详细例子

前言 SqlSugar 是一款老牌的 .NET 开源 ORM 框架&#xff0c;性能高&#xff0c;功能全面&#xff0c;使用简单&#xff0c;支持 .NET FrameWork、.NET Core3.1、.NET5、.NET6、.NET7、.NET8、.NET9 等版本&#xff0c;线上论坛非常活跃&#xff0c;今天给大伙分享一个 .Net c…

查看远程桌面端口,查看服务器的远程桌面端口的方法

如果你正在寻找一种方法来检查服务器的远程桌面端口&#xff0c;那么请务必按照以下步骤操作&#xff0c;以确保准确且安全地获取所需信息。这不仅是一个技术问题&#xff0c;更是一个关于效率和安全性的重要议题。 首先&#xff0c;你需要明确&#xff0c;远程桌面端口通常是…

【数据结构与算法 | 二叉树篇】二叉树的前中后序遍历(迭代版本)

1. 前言 前文我们实现了二叉树前中后三种遍历方式的递归版本&#xff0c;非常简单. 接下来我们来实现一下其迭代版本. 2. 二叉树的前序遍历 (1). 题 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2…

语音技能云云接入通用平台

Cloud-to-Cloud(云云接入) 前言 项目地址&#xff1a;https://github.com/LeYunone/cloud-to-cloud 配置说明&#xff1a;https://leyunone.com/github-project/voice-cloud-cloud-config.html 注&#xff1a;学习测试以及使用请拉取 master 分支&#xff0c;release 是开发…

python pip 安装

如果您不确定pip的安装路径&#xff0c;可以通过以下命令来查询&#xff1a; pip show pip 这个命令会显示pip的详细信息&#xff0c;其中包括pip安装的路径。如果您想修改pip的默认安装路径&#xff0c;可以使用pip的"--target"参数指定目标路径&#xff0c;例如&a…

8.7k Star!Khoj:你的AI第二大脑、开源RAG Cop​​ilot、平替 MS Copilot与ChatGPT

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 8.7k Star&#xff01;Khoj&#xff1a;你的AI第二大脑、开源RAG Cop​​ilot、平替 MS Copilot与ChatGPT &#x1f31f;你的AI第二大脑。…

zynq-7015启动分析及裸机BootLoader编写(未完待续)

使用lwip-tcp远程对QSPI进行更新、QSPI FLASH启动 W25Q128资料&#xff1a; W25Q128JV datasheet(1/78 Pages) WINBOND | 3V 128M-bit serial flash memory with dual/quad spi (alldatasheet.com) UG585资料&#xff1a; Zynq 7000 SoC Technical Reference Manual-UG585 翻译…

【ARFoundation自学05】人脸追踪(AR Face manager)实现

1. 修改摄像机朝向渲染方式-选中user 这个方式就会调用前置摄像头 2 创建 AR Session、XR Origin&#xff0c;然后在XR Origin上面添加组件 注意&#xff1a;XR Origin 老版本仍然叫 AR Session Origin 接下来在XR Origin上面添加AR Face Manager组件&#xff0c;如下图&am…

剧本杀市场仍在快速发展,剧本杀小程序成为了新的机遇

近年来&#xff0c;剧本杀一直是年轻人的娱乐游戏方式之一&#xff0c;剧本杀行业呈现出了井喷式发展的形势&#xff0c;成为了当下爆火的娱乐方式。目前&#xff0c;剧本杀行业拥有了完善的剧本资源和呈现方式&#xff0c;发展前景非常大。 根据当下的数据显示&#xff0c;剧…

NextJs 实现自定义点火操作

NextJs 实现自定义点火操作 前言实现自定义点火 前言 我希望在Nextjs 启动的时候&#xff0c;能够自定义实现一些项目的初始化逻辑&#xff0c;也可以说是一些点火操作&#xff0c;比如资源的加载&#xff0c;数据的初始化等操作。 实现自定义点火 我们可以在根目录下创建一…

Android 开机动画的启动过程BootAnimation(基于Android10.0.0-r41)

文章目录 Android 开机动画的启动过程BootAnimation(基于Android10.0.0-r41)1.开机动画的启动过程概述2.为什么设置了属性之后就会播放&#xff1f; Android 开机动画的启动过程BootAnimation(基于Android10.0.0-r41) 1.开机动画的启动过程概述 下面就是BootAnimation的重要部…

移动app测试重要性体现在哪些方面?专业app测试报告获取

移动app测试是指对手机应用进行各种测试和评估的过程&#xff0c;以确保应用的功能、性能和用户体验达到要求。在现代社会中&#xff0c;移动应用已经成为人们日常生活的一部分。无论是社交娱乐、购物支付还是工作学习&#xff0c;移动应用都发挥着不可替代的作用。因此&#x…

单元测试AIR原则:提升代码质量的秘密武器

文章目录 引言一、AIR原则1. Automatic&#xff08;自动化&#xff09;2. Independent&#xff08;独立性&#xff09;3. Repeatable&#xff08;可重复性&#xff09; 二、Automatic&#xff08;自动化&#xff09;三、Independent&#xff08;独立性&#xff09;四、Repeatab…

【MySQL】sql语句之表操作(上)

序言 在上一篇的数据库操作的内容中&#xff0c;学习了两种属性和常用的七种操作&#xff0c;学习是循序渐进的&#xff0c;库的操作学完了&#xff0c;就要开始学习表的操作了&#xff0c;而表可与数据强相关&#xff0c;比如DDL&#xff0c;即数据定义语言&#xff0c;DML&am…

DVWA-XSS(Stored)

Low 观察后端代码&#xff0c;对输入进行了一些过滤和转义。trim(string,charlist) 函数用于移除字符串两侧的空白字符或其他预定义字符&#xff0c;charlist 参数可以规定从字符串中删除哪些字符。stripslashes() 函数用于删除反斜杠。mysqli_real_escape_string() 函数用于对…

【实战】kafka3.X kraft模式集群搭建

文章目录 前言kafka2.0与3.x对比准备工作JDK安装kafka安装服务器增加hosts 修改Kraft协议配置文件格式化存储目录 启动集群停止集群测试Kafka集群创建topic查看topic列表查看消息详情生产消息消费消息查看消费者组查看消费者组列表 前言 相信很多同学都用过Kafka2.0吧&#xf…

tomcat配置请求的最大参数个数和请求数据大小

maxParameterCount"10000" maxPostSize"10485760" maxParameterCount&#xff1a;单个请求最大请求参数个数&#xff1b; maxPostSize&#xff1a;单个请求最大数据大小&#xff0c;1048576010M&#xff1b;