学习记录——day26 进程间的通信(IPC)无名管道 无名管道 信号通信 特殊的信号处理

目录

一、进程间通信引入

二、无名管道

1、无名管道相关概念

2、无名管道的API接口函数 pipe(int pipefd[2]);

3、管道通信的特点

4、管道的读写特点

 三、无名管道

1、有名管道:有名字的管道文件,其他进程可以调用

2、可以用于亲缘进程间的通信,也可以用于非亲缘进程间的通信

3、有名管道的API函数 mkfifo(const char *pathname, mode_t mode);

 四、信号通信

1、信号通信相关概念

2、信号通信相关指令: kil -  man 7 signal

3、将信号与信号处理方式连接函数

 五、特殊的信号处理

1、SIGCHLD信号:以非阻塞的形式回收僵尸进程

2、SIGALRM:定时器信号

3、信号的发送函数

 使用有名管道实现两个进程间相互通信

 使用有名管道实现,一个进程用于给另一个进程发消息,另一个进程收到消息后,展示到终端上,并且将消息保存到文件上


一、进程间通信引入

1、对于多个线程间的通信,可以使用使用临界资源来完成,通过一个线程任务对临界资源进行修改,另一个线程也可以使用已经修改过的临界资源,但是要注意使用同步互斥机制完成对临界资源的保护

2、对于进程而言,用户空间是独立的,全局变量也是独立拥有的,更改一个进程的全局变量,其他进程的全局变量不受影响

3、可使用文件完成进程间的通信,但是要求写进程先完成向文件中写入数据,然后读进程才能读取数据,必须要加入进程的同步操作

4、对于进程而言,内核空间是共享的,可通过内核空间存取数据的方式,来完成两个进程之间信息的交流

5、进程间通信方式:

1)内核提供的原始通信方式
        无名管道
        有名管道
        信号
2)system V提供三种方式
        消息队列
        共享内存
        信号量集

二、无名管道

1、无名管道相关概念

1)无名管道:没有名字的管道文件,其他进程不能使用无名管道文件的文件描述符,但可以遗传,所以该方法仅适用于亲缘进程(父子进程)

2)原理:,通过内核,在内存中创建出一个管道文件,存放在内存空间,并不在文件系统中真实存在。当打开该文件时,会返回该文件的两个文件描述符,分别对应读端和写端。可以通过读端从管道中读取数据,从写端向管道中写入数据。当该文件的读写两端全部被关闭后,该管道文件会在内存中消失

3)注意:由于打开管道时返回的是文件描述符,所以,对该文件的操作,只能使用文件IO;

               对于存入管道中的数据的读取是一次性的,当数据读取结束后,数据就不存在于管道文件中了

2、无名管道的API接口函数 pipe(int pipefd[2]);

       #include <unistd.h>

       int pipe(int pipefd[2]);
       功能:在通过内核在内存中创建一个无名管道,并通过参数将该管道文件的两个文件描述符返回
       参数:接收文件描述符的数组,pipefd[0]表示管道文件的读端,pipefd[1]表示管道的写端
       返回值:成功返回0,失败返回-1并置位错误码

#include <myhead.h>int main(int argc, char const *argv[])
{// 成绩用于通讯的管道an文件,并返回文件对应的ean文件as描述符int pipefd[2];if (pipe(pipefd) == -1){perror("pipe error");return -1;}// 创建子进程pid_t pid = fork();if (pid < 0){perror("fork error");return -1;}else if (pid == 0){// 子进程char rbuf[128] = "";// 关闭写端close(pipefd[1]);while (1){bzero(rbuf, sizeof(rbuf));read(pipefd[0], rbuf, sizeof(rbuf));if (strcmp(rbuf, "quit") == 0){break;}printf("收到父进程的信息:%s\n", rbuf);}// 关闭读端close(pipefd[0]);// 退出exit(EXIT_SUCCESS);}// 父进程char sbuf[128] = "";// 关闭读端close(pipefd[0]);while (1){usleep(10);printf("父进程中输入:");fgets(sbuf, sizeof(sbuf), stdin); // 从终端获取数据sbuf[strlen(sbuf) - 1] = 0;// 发送数据给子进程:将数据通过写端写入管道 pipefd[1]write(pipefd[1], sbuf, strlen(sbuf));if (strcmp(sbuf, "quit") == 0){break;}}// 关闭写端close(pipefd[1]);// 回收子进程wait(NULL);return 0;
}

注:对于单个进程,读写端一般只保留其中之一

3、管道通信的特点

1)管道通信是半双工的通信方式
    单工:任意时刻只能A向B发送消息,B不能向A发送消息
    半双工:同一时刻,只能A向B发送消息或者B向A发消息
    全双工:任意时刻,AB可以互相发送消息
2)无名管道只适用于亲缘进程间通信
3)无名管道也能完成自己跟自己的通信
4)无名管道文件的大小:64KB   2的16次方字节(65536)   

4、管道的读写特点

1)当管道读端存在时,写管道有多少写多少,直到写满64K为止
2)当管道读端不存在时,写管道写入数据时,会出现管道破裂,此时内核空间会向用户空间发送一个SIGPIPE信号
3)当写端存在时,读管道有多少读多少,没有数据会在read处阻塞
4)当写端不存在时,读管道有多少读多少,没有数据也不会在read处阻塞

 三、有名管道

1、有名管道:有名字的管道文件,其他进程可以调用

2、可以用于亲缘进程间的通信,也可以用于非亲缘进程间的通信

3、有名管道的API函数 mkfifo(const char *pathname, mode_t mode);

       #include <sys/types.h>
       #include <sys/stat.h>

       int mkfifo(const char *pathname, mode_t mode);
    功能:在文件系统中创建一个有名管道,但是并没有打开该文件
    参数1:有名管道的名称
    参数2:管道文件的权限
    返回值:成功返回0,失败返回-1并置位错误码

 四、信号通信

1、信号通信相关概念

1)信号通信原理图:两个异步通信的进程之间,通过发送相关信号,完成任务间的通信

2) 信号是linux中软件模拟硬件的“中断”的一种方式

4)对于信号的处理方式有三种:默认、捕获、忽略

6)信号的发送者可以是内核、其他进程、用户自己

      有两个信号既不能被捕获,也不能被忽略:SIGKILL、SIGSTOP(只要放入signal函数中就会报错:参数不合法)

2、信号通信相关指令: kil -  man 7 signal

1)能够发送的信号可以通过指令:kil - 进行查看

 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX    

2)上面的信号触发条件以及默认处理方式可以通过指令 man 7 signal 进行查看

       Signal     Value     Action   Comment
       ────────────────────────────────────────────────────────        SIGHUP        1       Term    Hangup detected on controlling terminal
                                                or death of controlling process
       SIGINT        2        Term    Interrupt from keyboard
       SIGQUIT       3      Core    Quit from keyboard
       SIGILL        4         Core    Illegal Instruction
       SIGABRT       6      Core    Abort signal from abort(3)
       SIGFPE        8       Core    Floating-point exception
       SIGKILL       9        Term    Kill signal
       SIGSEGV      11       Core    Invalid memory reference
       SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                                   readers; see pipe(7)
       SIGALRM      14       Term    Timer signal from alarm(2)
       SIGTERM      15       Term    Termination signal
       SIGUSR1   30,10,16    Term    User-defined signal 1
       SIGUSR2   31,12,17    Term    User-defined signal 2
       SIGCHLD   20,17,18    Ign     Child stopped or terminated
       SIGCONT   19,18,25    Cont    Continue if stopped
       SIGSTOP   17,19,23    Stop    Stop process
       SIGTSTP   18,20,24    Stop    Stop typed at terminal
       SIGTTIN   21,21,26    Stop    Terminal input for background process
       SIGTTOU   22,22,27    Stop    Terminal output for background process
 

3、将信号与信号处理方式连接函数

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);
       功能:将信号与信号处理函数绑定到一起
       参数1:要绑定的信号
       参数2:信号处理函数
               SIG_IGN:表示忽略信号
               SIG_DFL:表示默认处理
               填自定义函数的入口地址
        返回值:成功返回处理方式的起始地址,失败返回 SIG_ERR

 五、特殊的信号处理

1、SIGCHLD信号:以非阻塞的形式回收僵尸进程

#include <myhead.h>
void handler(int signo)
{if (signo == SIGCHLD){while(waitpid(-1,NULL,WNOHANG));}}
int main(int argc, char const *argv[])
{if (signal(SIGCHLD,handler) == SIG_ERR){perror("signal error");return -1;}for (int i = 0; i < 10; i++){if (fork() == 0){exit(EXIT_SUCCESS);return -1;}}for(;;);  //此处不使用while,是因为while对cpu的占用是100%,导致handler函数没有执行return 0;
}

2、SIGALRM:定时器信号

        程序允许启动一个定时器,当所定的时间到位后,会发送一个SIGALRM信号,将该信号绑定到对应的信号处理函数中,给定时间,到时间自动处理自定义函数

        该信号需要使用一个函数来发送超时信号:alarm闹钟函数

       #include <unistd.h>

       unsigned alarm(unsigned seconds);
    功能:给进程设置一个定时器,以秒为单位,当定时器到位后,后向该进程发送一个SIGALRM的信号
    参数:秒数,如果参数设置成0,表示删除定时器
    返回值:>0:表示返回的上一个定时器剩余的秒数,并且重置上一个定时器
                    0:表示之前没有设置定时器

3、信号的发送函数

       #include <signal.h>

       int kill(pid_t pid, int sig);
       功能:向指定的进程发送指定的信号
       参数1:要发送的进程号
           >0:表示向指定的进程发送信号
           =0:表示向某个进程组(当前进程所在的进程组)中发送信号
           =-1:向所有进程发送信号
           <-1:表示向其他进程组(组id为给定pid的绝对值)发送信号
       参数2:要发送的信号号
       返回值:      成功返回0,失败返回-1并置位错误码
       
       #include <signal.h>

       int raise(int sig);
       功能:向自己所在的进程发送指定的信号
       参数:要发送的信号
       返回值:成功返回0,失败返回非0数字
                    
 

 使用有名管道实现两个进程间相互通信

00.create.c  

#include <myhead.h>
int main(int argc, char const *argv[])
{// 创建一个有名管道文件if (mkfifo("./linux", 0664) == -1){perror("mkfifo error");return -1;}// 创建一个有名管道文件if (mkfifo("./linux1", 0664) == -1){perror("mkfifo error");return -1;}getchar();system("rm linux");system("rm linux1");return 0;
}

01snd.c

#include <myhead.h>
int main(int argc, char const *argv[])
{//创建子程序pid_t pid = fork();if (pid < 0){perror("fork error");return -1;}else if (pid == 0){// 以读的形式打开管道文件int rfd = open("./linux1", O_RDONLY);if (rfd == -1){perror("ropen error");return -1;}printf("./linux1 read open\n");// 接收数据char rbuf[128] = "";while (1){// 清空容器bzero(rbuf, sizeof(rbuf));// 读取数据read(rfd, rbuf, sizeof(rbuf));if (strcmp(rbuf, "quit") == 0){break;}printf("接收到:%s\n", rbuf);sleep(1);}// 关闭文件描述符close(rfd);exit(EXIT_SUCCESS);}// 以写的形式打开管道文件int wfd = open("./linux", O_WRONLY);if (wfd == -1){perror("wopen error");return -1;}printf("./linux write open\n");// 发送数据char wbuf[128] = "";while (1){printf("输入:");fgets(wbuf, sizeof(wbuf), stdin);wbuf[strlen(wbuf)-1] = 0;// 发送数据write(wfd, wbuf, strlen(wbuf));if (strcmp(wbuf, "quit") == 0){break;}}// 关闭文件描述符close(wfd);wait(NULL);return 0;
}

03recv.c

#include <myhead.h>
int main(int argc, char const *argv[])
{// 创建子程序pid_t pid = fork();if (pid < 0){perror("fork error");return -1;}else if (pid == 0){// 以写的形式打开管道文件int wfd = open("./linux1", O_WRONLY);if (wfd == -1){perror("open error");return -1;}printf("./linux1 write open\n");// 发送数据char wbuf[128] = "";while (1){printf("输入:");fgets(wbuf, sizeof(wbuf), stdin);wbuf[strlen(wbuf) - 1] = 0;// 发送数据write(wfd, wbuf, strlen(wbuf));if (strcmp(wbuf, "quit") == 0){break;}}// 关闭文件描述符close(wfd);exit(EXIT_SUCCESS);}usleep(10);// 以读的形式打开管道e文件int rfd = open("./linux", O_RDONLY);if (rfd == -1){perror("open error");return -1;}printf("./linux read open\n");// 接收数据char rbuf[128] = "";while (1){// 清空容器bzero(rbuf, sizeof(rbuf));// 读取数据read(rfd, rbuf, sizeof(rbuf));if (strcmp(rbuf, "quit") == 0){break;}printf("接收到:%s\n", rbuf);sleep(1);}// 关闭文件描述符close(rfd);wait(NULL);return 0;
}

 使用有名管道实现,一个进程用于给另一个进程发消息,另一个进程收到消息后,展示到终端上,并且将消息保存到文件上

00.create.c

#include <myhead.h>
int main()
{// 创建一个有名管道文件if (mkfifo("./file", 0664) == -1){perror("mkfifo error");return -1;}getchar();system("rm linux");return 0;
}

01.send.c

#include<myhead.h>int main()
{int wfd=open("./file",O_WRONLY);if(wfd==-1){perror("open error");return -1;}char buf[128]="";while(1){printf("请输入>>>");//从终端读取数据fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]=0; //末位置空('\0')//写入通道write(wfd,buf,strlen(buf));if(strcmp(buf,"quit")==0){break;}}//关闭文件操作符close(wfd);return 0;
}

02rece.c

#include<myhead.h>int main()
{int wfd=open("./lz",O_RDONLY);if(wfd==-1){perror("open error");return -1;}int pt=-1;if((pt=open("./text.txt",O_WRONLY|O_CREAT|O_TRUNC,0664))==-1){perror("open error");return -1;}char buf[128]="";while(1){//清空bzero(buf, sizeof(buf));//从通道读取数据read(wfd, buf, sizeof(buf));//判断离开if(strcmp(buf,"quit")==0){break;}printf("收到%s\n",buf);//写入文件write(pt,buf,strlen(buf));}//关闭文件指针close(pt);//关闭通道读写close(wfd);return 0;
}

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

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

相关文章

代码随想录训练营第五十二天 孤岛的总面积

第一题&#xff1a;孤岛的总面积 第二题&#xff1a;沉没孤岛 思路&#xff1a; 将所有在边界的岛屿所在的visited数组位置都置为true&#xff0c;剩下的visited[i][j] true && grid[i][j] 1的位置就是孤岛&#xff0c;将其置为1即可。 代码如下 #include <io…

【限免】通信信号与干扰信号【附MATLAB代码】

微信公众号&#xff1a;EW Frontier 关注可了解更多的雷达、通信、人工智能相关代码。问题或建议&#xff0c;请公众号留言; 个人博客&#xff1a;106.54.201.174 QQ交流群&#xff1a;949444104 摘要 本项目主要模拟仿真常见通信信号及干扰信号&#xff0c;高斯白噪声、噪声调…

NSF共享目录未授权访问

NSF共享目录未授权访问 Network File System(NFS)&#xff0c;是由SUN公司研制的UNIX表示层协议(pressentation layer protocol)&#xff0c;能使使用者访问网络上别处的文件就像在使用自己的计算机一样。服务器在启用nfs服务以后&#xff0c;由于fs服务未限制对外访问&#x…

无人机之导航系统篇

一、导航系统组成 包括惯性导航系统、卫星导航系统、视觉导航系统等。 二、导航原理 利用传感器感知无人机的位置、速度和姿态信息&#xff0c;结合地图数据和导航算法&#xff0c;计算出无人机当前的位置和航向&#xff0c;从而引导无人机按照预设的航线飞行。 三、导航精…

使用SpringBoot+Vue3开发项目(2)---- 设计文章分类的相关接口及页面

目录 一.所用技术栈&#xff1a; 二.后端开发&#xff1a; 1.文章分类列表渲染&#xff1a; 2.新增文章分类&#xff1a; 3.编辑文章分类&#xff1a; 4.删除文章分类 &#xff1a; 5.完整三层架构后端代码&#xff1a; &#xff08;1&#xff09;Controller层&#xff1a…

优化if-else的11种方案

优雅永不过时&#xff01; 1. 使用早返回&#xff08;Early Return&#xff09;&#xff1a;尽可能早地返回&#xff0c;避免嵌套的if-else。 优化前&#xff1a; public class NoEarlyReturnExample {public boolean hasPositiveNumber(int[] numbers) {boolean foundPositi…

学习大数据DAY31 Python基础语法4和基于Python中的MySQL 编程

目录 Python 库 模块 time&datetime 库 连接 MySQL 操作 结构操作 数据增删改操作 数据查询操作 上机练习 7 面向对象 OOP 封装 继承 三层架构---面向对象思想模型层 数据层 业务逻辑显示层 上机练习 8 三层架构开发豆瓣网 关于我对 AI 写代码的看法&#xf…

客户数据分析模型:RFM模型的深度解析与应用探索

RFM模型&#xff0c;作为客户数据分析中的经典工具&#xff0c;凭借其简单而强大的分析能力&#xff0c;被广泛应用于各行各业。本文旨在深入探讨RFM模型的核心原理、应用价值&#xff0c;并详细阐述其在2C&#xff08;面向消费者&#xff09;和2B&#xff08;面向企业&#xf…

使用ThreadLocal来存取单线程内的数据

一.什么是ThreadLocal&#xff1f; ThreadLocal&#xff0c;即线程本地变量。如果你创建了一个 ThreadLocal变量&#xff0c;那么访问这个变量的每个线程都会有这个变量的一个本地拷贝&#xff0c;多个线程操作这个变量的时候&#xff0c;实际是在操作自己本地内存里面的变量&…

自注意力和位置编码

一、自注意力 1、给定一个由词元组成的输入序列x1,…,xn&#xff0c; 其中任意xi∈R^d&#xff08;1≤i≤n&#xff09;。 该序列的自注意力输出为一个长度相同的序列 y1,…,yn&#xff0c;其中&#xff1a; 2、自注意力池化层将xi当作key&#xff0c;value&#xff0c;query来…

Ubuntu配置carla docker环境

前言: 本文只在以下设备成功运行, 其他设备不保证能成功, 可以参考在自己设备进行配置 环境 ubuntu 20.04carla 0.9.15gpu 3060(notebook) 安装显卡驱动&nvidia-container-toolkit 显卡驱动 安装完成系统后直接在’软件和更新->附加驱动’直接选择470(proprietary…

Leetcode3227. 字符串元音游戏

Every day a Leetcode 题目来源&#xff1a;3227. 字符串元音游戏 解法1&#xff1a;博弈论 分类讨论&#xff1a; 如果 s 不包含任何元音&#xff0c;小红输。如果 s 包含奇数个元音&#xff0c;小红可以直接把整个 s 移除&#xff0c;小红赢。如果 s 包含正偶数个元音&am…

R 语言学习教程,从入门到精通,R 基础运算(5)

1、R 基础运算 本章介绍 R 语言的简单运算。 1.1、赋值 一般语言的赋值是 号&#xff0c;但是 R 语言是数学语言&#xff0c;所以赋值符号与我们数学书上的伪代码很相似&#xff0c;是一个左箭头 <- &#xff1a; a <- 123 b <- 456 print(a b)以上代码执行结果…

最好用的掏耳勺是哪种?年度五款可视挖耳勺高分机型

在我们的日常生活中&#xff0c;掏耳朵似乎是一件再平常不过的小事&#xff0c;不过&#xff0c;传统挖耳勺在使用时完全依赖我们的感觉和经验&#xff0c;我们无法直接看到耳道内部的情况。这就如同在黑暗中摸索&#xff0c;极易造成意外伤害。稍有不慎&#xff0c;就可能刮伤…

使用gitea私有仓库作为依赖

实际问题 由于公司团队使用gitea搭建了git私有仓库&#xff0c;在开发Go程序的时候会有一些公共代码&#xff0c;比如插件和主程序之间要共享接口和数据结构&#xff0c;所以就需要在gitea私有仓库中创建依赖仓库&#xff0c;然后其他仓库引用这个私有仓库作为依赖。 解决方案…

如何实现pxe安装部署

此实验环境&#xff1a;rhel7主机 一、kickstart自动化安装脚本 1、安装可视化图形 [rootlocalhost ~]# yum group install "Server with GUI" 2、关闭vmware dhcp功能&#xff08;编辑-虚拟网络编辑器&#xff09; 3、httpd 1、安装httpd服务 [rootlocalhost …

网鼎杯比赛二次注入技巧

文章目录 前端的网页展示分析题目暴力破解寻找代码找到注入点进行注入查询想要的文件 前端的网页展示 分析题目 1.目前我们能看到的只有三个页面&#xff0c;但是我们可以看到三个*号。 2.考虑三个*的密码是什么&#xff0c;这里可以采用暴力破解&#xff08;我们先猜这是三个…

会声会影下载免费吗?会声会影2023中文旗舰版下载及配置最低要求

**会声会影2024&#xff1a;引领视频创作新时代的创新之旅** 在数字时代的浪潮中&#xff0c;视频创作已成为连接世界、表达创意的重要方式。随着技术的不断进步&#xff0c;一款名为“会声会影2024”的视频编辑软件横空出世&#xff0c;它不仅继承了前代产品的优秀传统&#…

C#MQTT协议应用

1 &#xff0c;MQTT介绍&#xff1a;MQTT详解以及实际操作_mqtt使用-CSDN博客 2&#xff0c;MQTT应用&#xff1a; C#MQTT编程06--MQTT服务器和客户端(winform版)_c# mqtt服务器-CSDN博客 3&#xff0c;MQTT实例&#xff1a; 效果 代码&#xff1a; 服务端 public parti…

通过Stack Overflow线程栈溢出的问题实例,详解C++程序线程栈溢出的诸多细节

目录 1、问题说明 2、从Visual Studio输出窗口中找到了线索,发生了Stack Overflow线程栈溢出的异常 3、发生Stack Overflow线程栈溢出的原因分析 4、线程占用的栈空间大小说明 5、引发线程栈溢出的常见原因和场景总结 6、在问题函数入口处添加return语句,在Debug下运行…