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_wait
        2.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函数只是注册了信号和处理方式的关系,并不会阻塞等待信号产生

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二叉搜索树(BST,Binary Search Tree)

目录 前言 一、二叉搜索树概念 二、二叉搜索树的实现与操作 1.查找 2.插入 3.删除 4.中序遍历 5.完整代码 三、二叉搜索树的应用&#xff08;K模型、KV模型&#xff09; 1.K模型 2.KV模型 3.完整代码 四、二叉搜索树的性能分析 前言 为何学&#xff1f; 1.二叉…

OceanBase 内存研究(OceanBase 3.2.4.5)

内存结构 从官网的结构图可以看出&#xff0c;一台observer可使用的总内存(memory_limit)包括 系统内存(system_memory) 和 租户内存(sys租户与普通租户) 系统内存 系统内存system_memory 属于 observer 的内部内存&#xff0c;允许其它租户共享使用该内存资源 (root10.0.0.…

vue2转vue3初步下载pnpm遇到的问题 pnpm : 无法加载文件 D:\nodejs\pnpm.ps1

安装pnpm npm install -g pnpm pnpm -v 提示&#xff1a; 解决&#xff1a;nvm install 18.18.0 下载最稳定版本的nodejs nvm use 18.18.0 然后注意重新下载删除pnpm npm uninstall -g pnpm npm install -g pnpmlatest 在vscode使用pnpm报错 解决&#xff1a;管理员运行Windo…

爬虫(没)入门:用 node-crawler 爬取 blog

起因 前几天想给一个项目加 eslint&#xff0c;记得自己曾经在博客里写过相关内容&#xff0c;所以来搜索。但是发现 csdn 的只能按标题&#xff0c;没办法搜正文&#xff0c;所以我没搜到自己想要的内容。 没办法只能自己又重新折腾了一通 eslint&#xff0c;很烦躁。迁怒于…

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

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

flutter3-os:基于flutter3.x+dart3+getx手机版os管理系统

flutter3-os-admin跨平台手机后台OS系统。 原创Flutter3.22Dart3.4Getxfl_chart等技术开发仿ios手机桌面OA管理系统。自研栅格化布局引擎、自定义桌面壁纸、小部件、底部Dock菜单、可拖拽悬浮球等功能。 全新自研栅格化OS菜单布局引擎。 使用技术 编辑器&#xff1a;VScode技术…

【架构模型】

一、客户端/服务端模式 二、单击应用模式 单机应用系统是最简单的软件结构&#xff0c;是指运行在一台物理机器上的独立应用程序。

【大模型】基于Hugging Face调用及微调大模型(1)

文章目录 一、前言二、Transformer三、Hugging Face3.1 Hugging Face Dataset3. 2 Hugging Face Tokenizer3.3 Hugging Face Transformer3.4 Hugging Face Accelerate 四、基于Hugging Face调用模型4.1 调用示例4.2 调用流程概述4.2.1 Tokenizer4.2.2 模型的加载4.2.3 模型基本…

spring源码初始学习基础-环境

环境&#xff1a;在这里插入代码片 allprojects {repositories {maven { url file:///D:/software/repository} // 本地仓库地址&#xff0c;如果没有依次向下寻找maven { url "https://maven.aliyun.com/repository/public" }mavenLocal()mavenCentral()}buildscri…

CopilotKit:开源 Copilot 框架,部署应用内 AI 代理,使用 Langchain 自动执行任何任务!

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; CopilotKit&#xff1a;开源 Copilot 框架&#xff0c;部署应用内 AI 代理&#xff0c;使用 Langchain 自动执行任何任务&#xff01; &am…

前端工程化工具系列(九)—— mddir(v1.1.1):自动生成文件目录结构工具

mddir 是一个基于项目目录结构动态生成 Markdown 格式目录结构的工具&#xff0c;方便开发者在文档中展示文件和文件夹的组织结构。 1. 安装 全局安装改工具&#xff0c;方便用于各个项目。 pnpm i -g mddir2. 使用 在想要生成目录接口的项目内打开命令行工具&#xff0c;输…

RocketMQ教程(一):RocketMQ的基本概念

RocketMQ是什么? RocketMQ 是一个分布式消息中间件和流计算平台,由阿里巴巴团队开源并贡献给 Apache 软件基金会,现为 Apache 顶级项目。它主要用于处理大规模数据的传输问题,支持高吞吐量、高可用性和可扩展性的消息发布和订阅服务。RocketMQ 能够确保消息的可靠传输,支持…

从报名到领证:软考高级【系统分析师】报名考试全攻略

本文共计13156字&#xff0c;预计阅读39分钟。包括七个篇章&#xff1a;报名、准考证打印、备考、考试、成绩查询、证书领取及常见问题。 不想看全文的可以点击目录&#xff0c;找到自己想看的篇章进行阅读。 一、报名篇 报名条件要求&#xff1a; 1.凡遵守中华人民共和国宪…

R语言探索与分析17-股票题目

Value at Risk&#xff08;VaR&#xff09;是一种统计技术&#xff0c;用于量化投资组合在正常市场条件下可能遭受的最大潜在损失。它是风险管理和金融领域中一个非常重要的概念。VaR通常以货币单位表示&#xff0c;用于估计在给定的置信水平和特定时间范围内&#xff0c;投资组…

码农危是否到来? AI大模型时代到来程序员能做啥?

前言 “马斯克提到人工智能会让工作变得毫无意义&#xff0c;并建议人们可能需要去编写人工智能程序&#xff0c;以避免被AI剥夺就业”&#xff0c;AI大模型的爆发&#xff0c;各种自动化编码应用工具&#xff0c;AI机器人出现&#xff0c;“前有2023年2月份&#xff0c;ChatG…

基于FPGA的任意点滑动平均(滑动窗长度和数据位宽参数化,例化时参数可设置)

目录 1.前言2.原理3.举例说明4.Matlab实现5.FPGA实现滑动平均 微信公众号获取更多FPGA相关源码&#xff1a; 1.前言 对于一维信号&#xff0c;我们可以使用类似移动平均滤波&#xff08;Moving Average Filtering&#xff09;实现denoising。Moving Average Filtering 是一种…

算法金 | 再见!!!KNN

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 KNN算法的工作原理简单直观&#xff0c;易于理解和实现&#xff0c;这使得它在各种应用场景中备受青睐。 我们将深入探讨KNN算法&…

微服务+分库分表的自增主键ID该如何设计?

一. 前言 分布式ID 是分布式系统里面非常重要的一个组成部分&#xff0c;那么我们在设计分布式ID的时候&#xff0c;需要考虑什么问题呢&#xff1f; ❓简单结构下是怎么实现 ID 的控制的&#xff1f; 单实例系统 &#xff1a;通过时间戳&#xff0c;系统内自增&#xff0c;上…

【高校科研前沿】新疆生地所陈亚宁研究员团队在GeoSus发文:在1.5°C和2°C全球升温情景下,中亚地区暴露于极端降水的人口增加

目录 文章简介 1.研究内容 2.相关图件 3.文章引用 文章简介 论文名称&#xff1a;Increased population exposures to extreme precipitation in Central Asia under 1.5 ◦C and 2 ◦C global warming scenarios&#xff08;在1.5C和2C全球变暖情景下&#xff0c;中亚地区…

flutter LINK : ...fatal error LNK1168: �޷���...

执行 flutter run -d windows 后报错 LINK : fatal error LNK1168: &#xfffd;޷&#xfffd;&#xfffd;&#xfffd; E:\xiaoli\flutter_project\huapu_update_hardware\build\windows\x64\runner\Debug\huapu_update_hardware.exe &#xfffd;&#xfffd;&#xfffd;…