linux线程间通讯----管道、信号

2023-11-19

 

进程间通讯机制:

unix继承: 管道、信号

system V IPC对象:共享内存、消息队列、信号灯集

1.管道

管道分为无名管道和有名管道--区别在于创建的管道是否在文件系统中不可见,无名不可见,有名可见。

(1)无名管道

特点:

1.在创建之后再文件系统中不可见

2.以半双工的方式进行通信,两根管道

3.拥有固定的读段和写段

4.只能用于具有亲缘关系的进程间通讯

(2)无名管道的功能函数

1.无名管道的创建--pipe()

#include <unistd.h>

int pipe(int pipefd[2]);

参数:
    pipefd:存放无名管道读段和写段的数组首地址
    pipefd[0]---读段
    pipefd[1]---写段
    
返回值:
    成功返回0,失败返回-1
    
练习:在一个进程中,创建一个子进程,子进程从键盘获取数据,父进程打印出数据

 

/*===============================================
*   文件名称:pipe.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:
================================================*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/types.h>
#include <wait.h>

int main(int argc, char *argv[])
{ 
    int pipefd[2]={0};	//文件描述符的空间
    char buf[64]={0};
    int ret=pipe(pipefd);	//创建无名管道
    if(ret<0)
    {
        perror("pipe");
        exit(-1);
    }
    pid_t pid=fork();	//创建子进程
    if(pid<0)
    {
        perror("fork");
    }
    if(pid==0)		//子进程
    {
        
        printf("请输入一串数据\n");
        scanf("%s",buf);
        write(pipefd[1],buf,strlen(buf));//写入无名管道
        memset(buf,0,64);		//清空缓冲区
        
    }
    else	//父进程
    {	
        sleep(1);		//等待子进程输完
        read(pipefd[0],buf,64);	//从无名管道读取数据
        printf("父:%s\n",buf);	//打印数据
        wait(NULL);    		//回收子进程
    }	

    return 0;
} 

2.无名管道的读写特性

读特性:

                写端存在:

                                管道有数据:返回读到得到字节数

                                管道无数据:read阻塞

                写段不存在:

                                管道有数据:返回读到的字节数

                                管道无数据:返回0

写特性:

                读段存在:

                                管道有空间:返回写入的字节数

                        管道无空间:write阻塞,直到有空间为止,有一个空间写一个字符

                读段不存在:

                        无论管道是否有空间,管道破裂,系统会发送SIGPIPE给当前进程,进程会死亡

练习:1.计算无名管道空间大小

                2.验证管道破裂

/*===============================================
*   文件名称:length_pipe.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:
================================================*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{ 
    int pipefd[2];
    pipe(pipefd);
    close(pipefd[0]);//关闭无名管道的读端
    pid_t pid=fork();
    if(pid<0)
    {
        perror("");
    }
    if(pid==0)
    {
        write(pipefd[1],"hello",5);
        sleep(3);//测试是否会正常退出
        
        /*int count=1,num=0;
        char buf[1024]={0}; 
        while(1)
        {
            count=write(pipefd[1],buf,1024);
            num+=count;
            printf("%d\n",num);   //测试管道大小
        }
        */
    }
    else
    {
        int status;
        wait(&status);//捕获信息
        printf("%d %d %d %d\n",WIFEXITED(status),WEXITSTATUS(status),WIFSIGNALED(status),WTERMSIG(status));
    }

    return 0;
} 

(3)有名管道

有名管道创建之后,会在文件系统中以管道文件的形式存在。

有名管道可以用于任意两个进程间通讯,没有固定的读端,写端

目录

1.管道

(1)无名管道

(2)无名管道的功能函数

1.无名管道的创建--pipe()

2.无名管道的读写特性

(3)有名管道

(4)有名管道的功能函数

2.信号

1.常用信号

2.信号相关指令

3.信号相关接口函数

4.定时器

5.捕获信号--signal


(4)有名管道的功能函数

1.有名管道的创建 -mkfifo()

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

int mkfifo(const char *pathname, mode_t mode);
参数:
    pathname:创建管道文件的文件名
    mode:表示创建的管道文件的权限,0664
    
返回值:
    成功返回0,失败返回1

练习:创建一个有名管道,一个进程向管道输入数据,另外一个向管道输出程序

输入程序:

/*===============================================
*   文件名称:mkfifo.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    /*
    int ret1=mkfifo("fifo",0664);//创建管道文件,已存在会保存
    if(ret1<0)
    {
        perror("mkfifo");
        exit(-1);
    }
    */
    int fp=open("fifo",O_RDWR);
    printf("fifo open\n");
    char buf[64]={0};
    int n=5;
    while(n--)
    {
        scanf("%s",buf);
        write(fp,buf,64);
    }


    close(fp);
    return 0;
} 

输出程序:

/*===============================================
*   文件名称:getfifo.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{ 
    int fd=open("fifo",O_RDWR);
    if(fd<0)
    {
        perror("open");
        exit(-1);
    }
    printf("fifo open \n");
    char buf[64]={0};
    int n=5;
    while(n--)
    {
        read(fd,buf,64);
        puts(buf);
        memset(buf,0,64);
    }
    close(fd);
    return 0;
} 

2.信号

信号:是终端在软件层次上的一种模拟

kill -l 常用信号 前32种是从unix继承而来。

型号的处理方式:

        默认处理:

        忽略处理:

        捕获信号:

1.常用信号

SIGHUP: (1) 终端的控制进程结束时

SIGINT: (2) (ctrl+c)结束前台进程

SIGQUIT: (ctrl +\ )

SIGLL: 进程企图执行一条非法指令时(可执行文件本身出错,堆栈溢出)段错误

SIGFPE:致命的算术运算错误,除数为0

SIGKILL:用来结束程序的运行,不能被阻塞、处理、忽略

SIGALRM:(14)定时器到时发出

SIGSTOP:用来暂停一个进程,不能被阻塞、处理、忽略

SIGTSTP:暂停交互过程(ctrl+z)

SIGCHLD:子进程改变状态时,父进程收到此信号

SIGABORT:用于结束进程

2.信号相关指令

kill -l:查看看单签系统中的所有信号

kill -信号编号 进程号 :向指定进程发送对应边好的信号

        eg:   kill -9 1234 向进程号为1234的进程发送信号9

                kill -9 -1234 (-负号)向进程组1234发送信号9

                kill -9 -1 向除了init以外的所有进程发送信号9

                kill -9 -0 信号被发送到所有和当前进程在同一进程组的进程

3.信号相关接口函数

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

int kill(pid_t pid, int sig);

参数:
    pid:指定的进程号
    sig:指定的信号,编号也可以
    
返回值:
    成功返回0,失败返回-1;

#include <signal.h>

int raise(int sig);

向当前进程发送信号
参数:
    sig:指定信号

返回值:
    成功返回0值,失败返回非0值

4.定时器

定时时间到,当前进程会接收到编号为14的SIGARLM信号,默认终止当前进程、

一个进程中,最多只能存在一个定时器。

定时器不改变原本函数的执行过程,只是计时,当程序运行时间超过定时器的时间,进程接收到SIGAELM信号

#include <unistd.h>

unsigned int alarm(unsigned int seconds);

参数:
    seconds:定时的秒数
        
返回值:
    成功,如果之前没有定时器,返回0。如果之前有定时器,返回其删一个定时器剩余时间
        
       eg:
        alarm(10);    返回值为0
        sleep(3);
        alarm(5);    返回值为10-3=7
            
        总定时时间为3+5=8,第二次调用ararm,刷新为5.
            
            
#include <unistd.h>
int pause(void);
功能:阻塞函数,等待定时结束

/*===============================================
*   文件名称:alarm.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:
================================================*/
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{ 
    int ret = alarm(5);
    printf("ret=%d\n",ret);
    sleep(3);
    
    ret=alarm(3);
    printf("ret=%d\n",ret);	//打印上次定时器的剩余时间
    sleep(6);

    return 0;
} 

5.捕获信号--signal

#include <signal.h>

typedef void (*sighandler_t)(int);

//等同于typedef void (*sighandler_t)(int) sighandler;

sighandler_t  signal(int signum, sighandler_t handler);

捕捉到信号就调用函数,而不是采用默认方式
参数:
    signum:指定信号,可填编号
    handler:信号处理函数或者SIG_IGN(选择以忽略方式处理指定信号)、SIG_DFL(选择以默认方式指定信号)
        信号处理函数不传参,参数为捕获到的型号的编号
返回值:


eg:
    signal(14,time_out)
    void time_out(int num)
    {
            printf("time_out %d",num);//num默认为捕获到的信号编号
    }
执行完函数之后,继续向下执行程序

练习:

创建一个子进程,子进程结束时,父进程提示子进程退出信息

SIGCHLD:子进程改变状态时,父进程收到此信号

/*===============================================
*   文件名称:signal.c
*   创 建 者:     
*   创建日期:2022年08月10日
*   描    述:
================================================*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>



void func(int num);
int main(int argc, char *argv[])
{ 
    pid_t pid = fork();//创建子进程
    if(pid<0)
    {
        perror("fork");
    }
    if(pid==0)//子进程
    {
        alarm(2);//定时2秒
        while(1)
        {

        	signal(14,func);//接收到信号,则执行func
        }
        //exit(0);
    }
    else
    {
        //kill(pid,9);
        int wstatus;
        signal(SIGINT,func);	
        signal(17,func);
        wait(&wstatus);	//回收子进程
        printf("%d %d %d %d\n",WIFEXITED(wstatus),WEXITSTATUS(wstatus),WIFSIGNALED(wstatus),WTERMSIG(wstatus));
    }
    return 0;
} 

void func(int num)
{
    printf("signal = %d\nchile is dead \n",num);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux线程间通讯----管道、信号 的相关文章

  • 标准头文件中的 C 编译器错误 - 未定义的 C++ 定义

    我正在尝试编译 C 程序 但收到许多错误 这些错误是在标准 C 头文件 inttypes h stdio h stat h 等 中遇到的 错误的来源是以下未定义的常量 BEGIN DECLS END DECLS BEGIN NAMESPAC
  • 在Linux中断上下文中运行用户线程

    我正在编写一些定制的应用程序 并允许更改 Linux 内核中的中断处理程序代码 我有一个用户线程正在等待中断发生 如果发生中断 那么我要做的第一件事就是执行该用户线程 有什么办法让它发挥作用吗 Thanks 创建一个字符设备 这就是内核所做
  • 每个进程每个线程的时间量

    我有一个关于 Windows 和 Linux 中进程和线程的时间量子的问题 我知道操作系统通常为每个线程提供固定的时间量 我知道时间量根据前台或后台线程而变化 也可能根据进程的优先级而变化 每个进程有固定的时间量吗 例如 如果操作系统为每个
  • 如何让“grep”从文件中读取模式?

    假设有一个很大的文本文件 我只想打印与某些模式不匹配的行 显然 我可以使用egrep v patter1 pattern2 pattern3 现在 如果所有这些模式都在一个文本文件中怎么办 最好的制作方法是什么egrep从文件中读取模式 g
  • 劫持系统调用

    我正在编写一个内核模块 我需要劫持 包装一些系统调用 我正在暴力破解 sys call table 地址 并使用 cr0 来禁用 启用页面保护 到目前为止一切顺利 一旦完成 我将公开整个代码 因此如果有人愿意 我可以更新这个问题 无论如何
  • 如何查找连接到 AF_INET 套接字的客户端的 UID?

    有什么方法或类似的东西ucred for AF UNIX如果是AF INET插座 TCP在我的例子中 找出连接到我的套接字的客户端的UID 还有 proc net tcp但它显示了UID of the creator插座的而不是连接的cli
  • Composer 安装要求

    我正在尝试将 Composer 安装到 Laravel 项目中 当我做的时候sudo composer install在项目目录中它显示了两个错误 Problem 1 Installation request for simplesoftw
  • arm-linux-gnueabi 编译器选项

    我在用 ARM Linux gnueabi gcc在 Linux 中为 ARM 处理器编译 C 程序 但是 我不确定它编译的默认 ARM 模式是什么 例如 对于 C 代码 test c unsigned int main return 0x
  • SONAR - 使用 Cobertura 测量代码覆盖率

    我正在使用声纳来测量代码质量 我不知道的一件事是使用 Cobertura 测量代码覆盖率的步骤 我按照以下步骤操作http cobertura sourceforge net anttaskreference html http cober
  • 在 Linux 上的 Python 中使用受密码保护的 Excel 工作表

    问题很简单 我每周都会收到一堆受密码保护的 Excel 文件 我必须解析它们并使用 Python 将某些部分写入新文件 我得到了文件的密码 当在 Windows 上完成此操作时 处理起来很简单 我只需导入 win32com 并使用 clie
  • 在 Mac OS X 上构建 Linux 内核

    我正在做一个修改Linux内核的项目 我有一台桌面 Linux 机器 在上面构建内核没有问题 不过 我要去旅行 我想在途中工作 我只有一台 MacBook 当我尝试构建 Linux 内核时 它抱怨说elf h was not found 我
  • Unix 命令列出包含字符串但*不*包含另一个字符串的文件

    如何递归查看包含一个字符串且不包含另一个字符串的文件列表 另外 我的意思是评估文件的文本 而不是文件名 结论 根据评论 我最终使用了 find name html exec grep lR base maps xargs grep L ba
  • Bash 解析和 shell 扩展

    我对 bash 解析输入和执行扩展的方式感到困惑 对于输入来说 hello world 作为 bash 中的参数传递给显示其输入内容的脚本 我不太确定 Bash 如何解析它 Example var hello world displaywh
  • 无法加载 JavaHL 库。- linux/eclipse

    在尝试安装 Subversion 插件时 当 Eclipse 启动时出现此错误 Failed to load JavaHL Library These are the errors that were encountered no libs
  • 如何通过替换为空页映射来取消映射 mmap 文件

    Linux 用户空间有没有办法用空页面 映射自 dev null 或者可能是一个空页面 重复映射到从文件映射的页面的顶部 对于上下文 我想找到这个 JDK bug 的修复 https bugs openjdk java net browse
  • 使用 grep 查找包含所有搜索字符串的行

    我有一个文件 其中包含很多与此类似的行 id 2796 some model Profile message type MODEL SAVE fields account 14 address null modification times
  • 如何使用 bash 锁定文件

    我有一个任务从远程服务器同步目录 rsync av email protected cdn cgi l email protection srv data srv data 为了使其定期运行并避免脚本 reEnter 问题 我使用 rsyn
  • 如何在 Linux 中编写文本模式 GUI? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 当我编写脚本 程序时 我经常想弹出一个简单的文本 gui 来提示输入 我该怎么做 例如 来自 Shel
  • 如何禁用 GNOME 桌面屏幕锁定? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何阻止 GNOME 桌面在几分钟空闲时间后锁定屏幕 我已经尝试过官方手册了在红帽 https access redhat com doc
  • Linux TUN/TAP:无法从 TAP 设备读回数据

    问题是关于如何正确配置想要使用 Tun Tap 模块的 Linux 主机 My Goal 利用现有的路由软件 以下为APP1和APP2 但拦截并修改其发送和接收的所有消息 由Mediator完成 我的场景 Ubuntu 10 04 Mach

随机推荐

  • 二进制.bin文件切分、bintopng、write

    import numpy as np import cv2 import os Your file path file dep open r E data 3DHuman Detection withoutlabel 20180715 50
  • 小白入门机器学习深度学习实战教程

    课程介绍 机器学习深度学习 实战训练营开课了 哔哩哔哩 bilibili 机器学习深度学习 实战训练营开课了
  • Leetcode——350. 两个数组的交集 II

    题目 给你两个整数数组 nums1 和 nums2 请你以数组形式返回两数组的交集 返回结果中每个元素出现的次数 应与元素在两个数组中都出现的次数一致 如果出现次数不一致 则考虑取较小值 可以不考虑输出结果的顺序 输入 nums1 1 2
  • 关于gitee的用法

    一 安装git 安装git git version 查看版本 创建仓库 git 全局配置 git config global user name huangkaihk git config global user email 邮箱 git
  • 2.6.1 ADSL技术

    ADSL技术 即 非对称数字用户线技术 利用 数字技术 对 现有的 模拟电话用户线 进行改造 使其能够承载宽带数字业务 标准模拟电话信号的 频带 被限制在 300 3400 Hz 的范围内 无法承载宽带数字业务 但 用户线本身 可通过的 信
  • 超详细!4小时开发一个SpringBoot+vue前后端分离博客项目!!

    小Hub领读 前后端分离的博客项目终于出来啦 真是花了好多心思录制咧 文末直接进入B站看视频哈 这次你找不到不关注我B站的理由了吧 作者 吕一明 项目代码 https github com MarkerHub vueblog 项目视频 ht
  • Unity卡死情况

    今天遇到了Unity点击播放后卡死 用任务管理器强行关闭后重开 打不开项目的情况 解决方案 检查USB接口设备 有些设备可能会影响Unity工程启动 比如VR头盔
  • 使用java代码给Excel加水印,代码全,进阶版

    以下代码 亲测可以跑通 1 上一篇博客用了Apache POI库3 8的版本的形式对Excel加了水印 但是最近主线版本用了4 1 2的形式 由于为了保持版本的兼容性 下面有开发了Apache POI的4 1 2的版本号的方案 pom文件为
  • 使用selenium IDE开始简易自动化测试

    使用selenium IDE开始简易自动化测试 火狐浏览器有个很好用的selenium插件 可以自动录制页面动作 selenium IDE 下载地址 下载安装好 笔者下载的2 9 0 我们以在百度搜索selenium为例 首先启动IDE 点
  • 链式二叉树的基本操作(C语言实现)

    目录 一 链式二叉树的创建 1 1 定义节点结构 1 2 节点的创建 1 3 节点的链接 二 树的深度遍历 1 前序 中序 后序遍历 1 2 三种方式的遍历顺序图 2 代码实现 3 遍历检测 三 树的层序遍历 3 1 层序遍历 3 2 完全
  • Loadrunner录制登录,验证是否登录成功的几种方法

    1 利用web reg find 优先使用 2 利用web image check 其次 3 利用web get int property函数 4 利用提交的status状态 5 利用对数据的操作查看是否登录 1 利用添加检查点web re
  • 拼多多招收java开发的三轮面试题,你能撑到第几轮?

    我相信 面试一直是大家关注的问题 包括最近有很多刚毕业或者刚实习的小伙伴跟我讲投了很多简历出去 但却都像泥牛入海一样了无音讯了 确实出于程序员的直觉 今年着实是要比往年要更冷一些 对于面试来说 我相信大家都听过一个说法就是 金九银十 但是现
  • c++/cuda并行累计求和

    文章目录 代码 CMakeLists txt 结果 代码 include
  • 设计模式-建造者模式

    文章目录 建造者模式 创建复杂对象的优雅方式 什么是建造者模式 建造者模式的使用场景 优缺点 示例 使用建造者模式创建电脑对象 建造者模式 创建复杂对象的优雅方式 在软件开发中 有时候我们需要创建具有复杂结构和多个组件的对象 直接在客户端代
  • 【Pytorch异常笔记】Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.

    文章目录 异常描述 解决方法 开发环境 异常描述 OMP Error 15 Initializing libiomp5md dll but found libiomp5md dll already initialized OMP Hint
  • git 和远程服务器关联,Git远程服务器连接被拒绝

    我对这个错误感到疯狂 2天后我没有发现我的系统出了什么问题 我相信修复它非常容易 Git远程服务器连接被拒绝 当我尝试使用Git功能我得到的消息 连接到我的git服务器 无法打开连接 主机不存在 致命的 无法从远程存储库中读取 请确保您拥有
  • Android JNI1--C语言基础

    1 include 相当于java的导包操作 例如 include
  • vue中computed的属性对data中的属性赋值为undefined的原因

    场景 我在computed中return了一个值 然后在data中直接将它复制给另一个属性 结果data中的属性值为undefined 代码示例 timer为undefined 原因 在这里很容易想到是执行顺序的问题 computed中的属
  • sql server 中的日期计算,如当天周的第一天,当前月的第一天

    根据给定的日期 计算该日期在本月所在周数 每周的第一天为周日 但是在月末需要与下个月进行衔接 如 图2012年2月份 3月份的1 2 3号为2月份的第4周 而2月份的1 2 3 4为1月份的最后一周 第五周 declare datetime
  • linux线程间通讯----管道、信号

    进程间通讯机制 unix继承 管道 信号 system V IPC对象 共享内存 消息队列 信号灯集 1 管道 管道分为无名管道和有名管道 区别在于创建的管道是否在文件系统中不可见 无名不可见 有名可见 1 无名管道 特点 1 在创建之后再