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

news2024/10/7 20:24:52

文章目录

  • 一、 线程的同步
    • (一)无名信号量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函数只是注册了信号和处理方式的关系,并不会阻塞等待信号产生

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

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

相关文章

yum进阶——配置yum源

一、yum概述 yum的主要作用 解决依赖关系 自动安装 自动升级 各个系统中的安装软件服务 CentOS7 &#xff1a;yum -y 安装 rpm包 CentOS8 &#xff1a;dnf&#xff08;yum的升级版&#xff09;&#xff0c; Ubantu(22.04) &#xff1a;apt -y 安装&#xff0c;安装源为/…

【Python报错】已解决ModuleNotFoundError: No module named ‘packaging’

成功解决“ModuleNotFoundError: No module named ‘packaging’”错误的全面指南 在Python编程中&#xff0c;遇到ModuleNotFoundError: No module named packaging这样的错误&#xff0c;通常意味着你的Python环境中缺少名为packaging的模块&#xff0c;或者该模块没有被正确…

sing-task message

文章目录 1.起因2.查因过程2.1 定位job2.2 定位sql text2.3 定位db_link2.4 测试dblink2.5 tnsping host2.6 检查host信息2.7检查网路状况 3.处置办法&#xff1a;4.结论 1.起因 在巡查长事务时&#xff0c;有两个事务执行了很长时间没有完成 SELECT SE.SID,SE.SERIAL#,to_ch…

CEC2017(Python):五种算法(SSA、RFO、OOA、PSO、GWO)求解CEC2017

一、5种算法简介 1、麻雀搜索算法SSA 2、红狐优化算法RFO 3、鱼鹰优化算法OOA 4、粒子群优化算法PSO 5、灰狼优化算法GWO 二、CEC2017简介 参考文献&#xff1a; [1]Awad, N. H., Ali, M. Z., Liang, J. J., Qu, B. Y., & Suganthan, P. N. (2016). “Problem defin…

gitee和github的协同

假设gitee上zhaodezan有一个开发库&#xff0c;但是从andeyeluguo上拉取最新的&#xff08;从github上同步过来最新的&#xff09; git remote add dbgpt_in_gitee https://gitee.com/andeyeluguo/DB-GPT.git remote -v git pull --rebase dbgpt_in_gitee main 有冲突可能需要…

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

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

【漏洞复现】用友NC downCourseWare 任意文件读取漏洞

0x01 产品简介 用友NC是一款企业级ERP软件。作为一种信息化管理工具&#xff0c;用友NC提供了一系列业务管理模块&#xff0c;包括财务会计、采购管理、销售管理、物料管理、生产计划和人力资源管理等&#xff0c;帮助企业实现数字化转型和高效管理。 0x02 漏洞概述 用友NC …

上市即交付,比亚迪秦L DM-i万人交车暨千媒众测开营

6月6日&#xff0c;“引领中级 开创油耗2时代”秦L DM-i万人交车暨千媒众测开营仪式在比亚迪大本营深圳盛大举行。 众多车主代表亲临现场&#xff0c;与全国各地的比亚迪4S店千店联动&#xff0c;将秦L DM-i全国交付推向新的高潮。发布即量产&#xff0c;上市即交付&#xff0…

【NLP】2、大语言模型综述

一、背景和发展历程 大语言模型四个训练阶段&#xff1a; 预训练&#xff1a; 利用海量的训练数据&#xff0c;包括互联网网页、维基百科、书籍、GitHub、 论文、问答网站等&#xff0c;构建包含数千亿甚至数万亿单词的具有多样性的内容。利用由数千块高性能 GPU 和高速网络组成…

【图像处理与机器视觉】XJTU期末考点

题型 选择&#xff1a;1 分10 填空&#xff1a;1 分15 简答题&#xff08;也含有计算和画图&#xff09;&#xff1a;10 分*4 计算题&#xff1a;15 分20 分 考点 选择题&#xff08;部分&#xff09; 数字图像处理基础 p(x,y),q(s,t)两个像素之间的距离由公式&#xff1a…

HBuilderX打包uni-app项目成安卓app

目录 1、下载Android 离线SDK 2、Android Studio导入工程 3、生成签名 3.1、进入到jdk bin目录下&#xff0c;输入cmd执行命令keytool -genkey -alias wxsalias -keyalg RSA -keysize 2048 -validity 36500 -keystore wxs.keystore 生成签名 3.2、查看签名密钥keytool -lis…

C语言实现教学计划编制问题,Dev C++编译器下可运行(240606最新更新)

背景&#xff1a; 问题描述 大学的每个专业都要编制教学计划。假设任何专业都有固定的学习年限&#xff0c;每学年含两学期&#xff0c; 每学期的时间长度和学分上限都相等。每个专业开设的课程都是确定的&#xff0c;而且课程的开设时间的安排必须满足先修关系。每个课程的先…

最优化练习题

def f(x):return x*x-4*x5 a0,b01,31、均匀搜索 令 δ ( b 0 − a 0 ) / N , a i a 0 i δ , i 1 , 2 , 3 \delta(b_0-a_0)/N,a_ia_0i\delta,i1,2,3 δ(b0​−a0​)/N,ai​a0​iδ,i1,2,3 while b0-a0>0.1:anp.linspace(a0,b0,5)for i in range(1,4):if f(a[i-1])>f…

宝兰德受邀出席第八届丝绸之路网络安全论坛

近日&#xff0c;2024第八届丝绸之路网络安全论坛在陕西宾馆会议中心成功举办&#xff0c;本次论坛以“汇聚万千智慧 夯实安全堤坝”为主题&#xff0c;由主论坛及密码技术与密评、教育行业网络安全、卫健行业网络安全三个平行分论坛组成&#xff0c;论坛邀请业内专家学者、企业…

Pinia(三): 了解和使用state

1.state state 就是我们要定义的数据, 如果定义 store 时传入的第二个参数是对象, 那么 state 需要是一个函数, 这个函数的返回值才是状态的初始值.这样设计的原因是为了让 Pinia 在客户端和服务端都可以工作 官方推荐使用箭头函数(()>{ })获得更好的类型推断 import { de…

如何在Windows 10和11上修复DISM错误87?这里提供办法

​在电脑上运行DISM命令时,是否收到“错误代码87”消息?这是一个非常常见的错误,你可以轻松地修复它。我们将向你展示在Windows 11或Windows 10计算机上解决此问题的多种方法。 确保键入正确的命令 运行DISM命令时出现错误代码87的最常见原因是键入的命令不正确。你可能添…

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

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

【简单讲解下TalkingData】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

六位一线AI工程师总结Agent构建经验,天工SkyAgents的Agent构建实战。

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 六位一线AI工程师总结Agent构建经验&#xff0c;天工SkyAgents的Agent构建实战。 &#x1f31f;我们给人类新手明确的目标和具体的计划&am…

ATFX汇市:加拿大央行已宣布降息25基点,欧央行降息预期大幅增强

ATFX汇市&#xff1a;加拿大中央银行6月利率决议宣布&#xff0c;将政策利率下调25个基点至4.75%&#xff0c;时隔4年零三个月后再次进入降息周期。以2023年7月份加拿大央行最后一次加息算起&#xff0c;5.5%的高利率维持了11个月&#xff0c;期间加拿大的核心通胀率从6.2%降低…