【Linux】实验四 进程信号通信

2023-05-16

文章目录

  • 一、实验目的
  • 二、 实验内容
  • 三、 实验原理
    • 1、信号
      • 3.1.1 信号的基本概念
      • 3.1.2、信号的发送
    • 2、所涉及的系统函数调用
      • 3.2.1 fork()
      • 3.2.2 kill( )
        • This is my question.
      • 3.2.3 signal( )
        • 代码例子
      • 3.2.4 getpid()
      • 3.2.5 wait()
  • 四、 实验内容
  • 五、程序代码
    • 运行结果
  • 六、实验总结及心得体会:
    • 心得:
    • 思考题:
  • 每天进步一点点 笔记仅供自学,用来回看复习,不一定适合你,如有错误请指出。

一、实验目的

1、了解什么是信号
2、了解和熟悉 LINUX 支持的信号量机制
3、熟悉 LINUX 系统中进程之间软中断通信的基本原理

二、 实验内容

1、根据 4.1 程序流程图,设计程序。用 fork( )创建两个子进程,再用系统调用 signal( )让父进程捕捉键盘上来的中断信号(即按^c 键);
捕捉到中断信号后,父进程用系统调用 kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Child process1 is killed by parent!
Child process2 is killed by parent!

父进程等待两个子进程终止后,输出如下的信息后终止:
Parent process is killed!
2、分析利用软中断通信实现进程同步的机理

三、 实验原理

1、信号

3.1.1 信号的基本概念

每个信号都对应一个正整数常量(称为 signal number,即信号编号。

  1. 定义在系统头文件<signal.h>中),代表同一用户的各个进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件

  2. 每个进程在运行时,都要通过信号机制来检查是否有信号到达。
    – 若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;
    – 处理结束后再返回到原来的断点继续执行。

  3. 实质上,信号机制是对中断机制的一种模拟,故在早期的 UNIX 版本中又把它称为软中断

信号与中断的相似点

  1. 采用了相同的异步通信方式;
  2. 当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
  3. 都在处理完毕后返回到原来的断点;
  4. 对信号或中断都可进行屏蔽。

信号与中断的区别

  1. 中断有优先级,而信号没有优先级,所有的信号都是平等的;
  2. 信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;
  3. 中断响应是及时的,而信号响应通常都有较大的时间延迟。

信号机制具有以下三方面的功能

  1. 发送信号。发送信号的程序用系统调用 kill( )实现;
  2. 预置对信号的处理方式。接收信号的程序用 signal( )来实现对处理方式的预置;
  3. 收受信号的进程按事先的规定完成对相应事件的处理。

3.1.2、信号的发送

信号是操作系统用于通知进程的特殊事件。信号可以由系统内核发送,也可以由其他进程或用户发送。

  • 当系统内核发送信号时,通常是用于报告某些错误或异常情况,例如内存访问越界、无效指令等。
  • 当其他进程或用户发送信号时,通常是用于控制其他进程的行为。例如,使用kill命令可以向其他进程发送信号,控制其终止、暂停或继续执行。
  • 在 C/C++ 中,可以使用 kill 函数来发送信号。

进程用 kill( )向一个进程或一组进程发送一个信号。


2、所涉及的系统函数调用

3.2.1 fork()

系统调用格式: pid_t fork( void); 
#include <sys/types.h>
#include <unistd.h>

pid_t 是一个宏定义,其实质是 int 被定义在#include<sys/types.h>中

功能:创建子进程
返回值: 若成功调用一次则返回两个值
子进程返回 0
父进程返回 子进程 ID
否则,出错返回 -1.

函数说明:

  • 一个现有进程可以调用 fork 函数创建一个新进程。由 fork 创建的新进程被称为子进程(child process)。
  • fork 函数被调用一次,返回两次。两次返回的唯一区别是子进程中返回 0 值而父进程中返回子进程 ID。

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。

注意,

  • 子进程持有的是上述存储空间的 “副本”,这意味着父子进程间不共享这些存储空间。
  • linux 将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。

3.2.2 kill( )

系统调用格式: int kill(pid,sig)
#include <sys/types.h>
#include <signal.h>

参数定义 int pid,sig;
其中,pid 是一个或一组进程的标识符,参数 sig 是要发送的软中断信号。
(1)pid>0 时,核心将信号发送给进程 pid
(2)pid=0 时,核心将信号发送给与发送进程同组的所有进程
(3)pid=-1 时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。

This is my question.

当 pid 参数的值等于 -1 时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。这句话什么意思?

  • 核心将信号发送给具有与发送进程相同的有效用户标识符的所有进程。
  • 有效用户标识符是指系统分配给用户的唯一标识符,用于标识用户身份。

例如,如果你的有效用户标识符是 1000,那么当你使用 kill(-1, sig) 发送信号时,核心会将信号发送给所有具有有效用户标识符 1000 的进程。


3.2.3 signal( )

预置对信号的处理方式,允许调用进程控制软中断信号。

系统调用格式: signal(sig,function)
 #include <signal.h>

参数定义
signal(sig,function)

  • int sig;
  • void (*func) ( )

其中 sig 用于指定信号的类型,sig 为 0 则表示没有收到任何信号,

余者如下表:
在这里插入图片描述
在这里插入图片描述
function:在该进程中的一个函数地址,在核心返回用户态时,它以软中断信号的序号作为参数调用该函数,对除了信号 SIGKILL、SIGTRAP 和SIGPWR 以外的信号,核心自动地重新设置软中断信号处理程序的值为 SIG_DFL,一个进程不能捕获 SIGKILL 信号。
function 的解释如下:

(1)function=1 时,进程对 sig 类信号不予理睬,亦即屏蔽了该类信号;
(2)function=0 时,缺省值,进程在收到 sig 信号后应终止自己;
(3)function 为非 0,非 1 类整数时,function 的值即作为信号处理程序的指针。

代码例子

#include <stdio.h>
#include <signal.h>
// 信号处理程序
void sigint_handler(int signum) 
{
	printf("收到 SIGINT 信号!\n");
}
int main(int argc, char*argv[]) 
{
// 设置 SIGINT 信号的处理程序
	signal(SIGINT, sigint_handler);
	return 0;
}

在上面的程序中,当收到 SIGINT 信号时,程序会调用 sigint_handler() 函数。你可以在这个函数内部执行任何你希望在收到信号时执行的操作。


3.2.4 getpid()

pid_t getpid(void)
#include <sys/types.h>
#include <unistd.h>

功能:获取自己的进程 ID 号
参数:无
返回值:本进程的 ID 号


3.2.5 wait()

pid_t wait(int *wstatus);
#include <sys/wait.h>

功能:等待进程状态变化


四、 实验内容

在这里插入图片描述
程序所需头文件如下:

#include <stdio.h> //stdin, stdout, stderr,scanf(),printf()
#include <stdlib.h> //exit()
#include <signal.h> //signal()
#include <unistd.h> //getpid()
#include <sys/wait.h> //wait()

五、程序代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#define SIG17 17
#define SIG16 17
#define SIG2  17

//定义全局变量
pid_t child_pid1,child_pid2;

/*信号中断函数*/
void sigint_handler(int signum)
{
  // 向两个子进程发送信号
  kill(child_pid1, SIGINT);
  kill(child_pid2, SIGINT);
}

/*子程序中断函数*/
void child_handler(int signum) 
{
  printf("child process %d is killed by parent!\n", getpid());
  exit(0); 
}

/*主函数*/
int main(int argc, char *argv[]) 
{
  // 创建两个子进程
  child_pid1 = fork();
  if (child_pid1 == 0) 
  {
    // 这是第一个子进程
    signal(SIGINT, child_handler);
    while (1) 
    {
      sleep(1);
    }
  }

  child_pid2 = fork();
  if (child_pid2 == 0) 
  {
    // 这是第二个子进程
    signal(SIGINT, child_handler);
    while (1) 
    {
      sleep(1);
    }
  }

  // 输出父进程和子进程的 PID
  printf("parent PID:%d\n", getpid());
  printf("child1 PID:%d\n", child_pid1);
  printf("child2 PID:%d\n", child_pid2);

 //使用信号类型 2 暂停父进程
  printf("stop PID:%d by signal 2\n", getpid());
  kill(getpid(), SIG2);

  // 使用信号类型 17 暂停子进程 2
  printf("stop PID:%d by signal 17\n", child_pid2);
  kill(child_pid2, SIG16);

  // 使用信号类型 16 暂停子进程 1
  printf("stop PID:%d by signal 16\n", child_pid1);
  kill(child_pid1, SIG17);

  // 使用信号类型 2 暂停两个子进程
  printf("stop PID:%d by signal 2\n", child_pid1);
  printf("stop PID:%d by signal 2\n", child_pid2);
  kill(child_pid2, SIG2);
  kill(child_pid1, SIG2);

  // 为父进程设置信号处理程序
  signal(SIGINT, sigint_handler);

  // 等待两个子进程终止
  waitpid(child_pid1, NULL, 0);
  waitpid(child_pid2, NULL, 0);

  printf("Parent peocess is killed!\n");

  return 0;
}


运行结果

在这里插入图片描述

六、实验总结及心得体会:

心得:

  1. 在这个实验中,我使用了 fork()函数来创建子进程,并使用 signal()函数来处理信号,使用 kill()函数来发送信号。还使用了 wait()函数来等待子进程的终止,并使用 exit()函数来退出进程。
  2. 通过这个实验,我更好地了解进程的工作原理,包括进程的创建、信号的发送和接收以及进程的终止。这对于我们编写多进程程序是非常有帮助的

思考题:

  1. 当首次调用新创建进程 fork()时,其入口在哪里?

答:当首次调用 fork() 函数创建新进程时,该进程的入口在函数调用处。也就是说,新进程将从 fork() 函数调用的位置开始执行,而不是从函数的开头开始执行。


  1. 程序段中调用 wait(0)起什么作用?

答:wait() 函数是一个系统调用,用于让当前进程等待其子进程的终止。它的第一个参数可以是一个指向某个整型变量的指针,用于存储子进程的终止状态。如果不希望父进程获取子进程的终止状态,可以将参数设置为 0。
当调用 wait(0) 时,当前进程会等待其任意子进程的终止,然后返回该子进程的终止状态。


  1. 程序段中每个进程退出时都用了语句 exit(0),为什么?

答: exit(0) 函数用于终止当前进程,并返回一个状态码。这里的状态码是 0,表示进程正常结束。


每天进步一点点 笔记仅供自学,用来回看复习,不一定适合你,如有错误请指出。

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

【Linux】实验四 进程信号通信 的相关文章

  • telnet是什么

    Telnet是远程连接服务 xff0c 它工作于tcp ip协议的应用层 telnet命令通常用来远程登录 是Internet远程登陆服务的标准协议和主要方式 它为用户提供了在本地计算机上完成远程主机工作的能力 在终端使用者的电脑上使用te
  • 头文件与库文件的区别

    一 头文件与库文件的区别 头文件一般而言 xff0c 是申明和定义 库文件是已经编译好的二进制代码 这个二进制代码可以是动态的 xff0c 如 so xff1b 也可以是静态的 xff0c 如 a 如果是动态的 xff0c 则最后生成的程序
  • C++入门 vector的使用 + 进阶【模拟实现】

    目录 基本接口函数介绍迭代器空间容量增删查改迭代器失效问题探讨 vector模拟实现reserve迭代器空间容量删除insert析构函数vector拷贝构造函数拷贝赋值运算符 基本接口函数介绍 函数名功能vector xff08 重点 xf
  • C++11:继承

    目录 继承的基本概念 继承方式 基类和派生类对象赋值转换 切片 继承中的作用域 派生类的四个成员函数 xff1a 构造函数 拷贝构造函数 赋值重载 析构函数 静态成员 继承与友元 多继承 菱形继承 多继承的指针偏移问题 组合 继承的基本概念
  • socket编程二十六:基于UDP的服务器端和客户端

    前面的文章中我们给出了几个 TCP 的例子 xff0c 对于 UDP 而言 xff0c 只要能理解前面的内容 xff0c 实现并非难事 UDP中的服务器端和客户端没有连接 UDP 不像 TCP xff0c 无需在连接状态下交换数据 xff0
  • 下载高清电影的必须收藏的网站

    下载高清电影的必须收藏的网站 Posted 2012 12 06 分类 生活范儿 电影 生活范儿 电影 CHD 虽然蓝光推出 xff0c 但是高清已经势不可挡 xff0c 动辄几G甚至几十G一部的电影冲击着我们的视觉 xff0c 也考验着我
  • 电赛总结|电赛注意事项

    电赛总结 赛前 1 准备模块非常重要 如果没有提前准备模块 xff0c 在赛中也是在想尽办法买模块 xff0c 只是花更多的钱和运费等 xff0c 也不会去自己搭 所以赛前一定要准备模块 常见模块 降压模块 xff0c 升压稳压模块 xff
  • Putty使用教程

    Putty作为免费且开源的老牌 SSH 客户端 xff0c PuTTY 经常用于 Windows 下连接管理远程服务器 为方便刚接触 VPS 的新手参考使用 xff0c 本文配合截图介绍 PuTTY 的基础用法及一些设置技巧 xff0c 希
  • #Python实现话题的发布与订阅

    Python实现话题的发布与订阅 首先我们的先了解ROS文件系统的基本框架 xff0c 如下图所示 xff1a 由上图可知 xff0c py文件放在工作包里面的scripts文件夹内 xff0c 所以 xff0c 整活 xff01 1 在工
  • #创建自定义topic

    创建自定义topic 前面我们学了用C 43 43 和Python创建发布者与订阅者 xff0c 这次我们创建自定义的话题 xff0c 其实同C 43 43 实现topic差不多 xff0c 都是编写 cpp文件 步骤有点多且繁琐 xff0
  • #使用TF实现海龟机器人跟随

    使用TF实现海龟机器人跟随 昨天粗略地讲解了一会儿TF变换 xff0c 用的是ROS系统中自带的功能包实现小海龟跟随的功能 xff08 具体见 初识TF变换 xff09 今天我们将用自己编写节点的方式实现小海龟跟随的功能 xff0c 并且
  • #创建虚拟机器人URDF模型

    创建虚拟机器人URDF模型 题外话 xff1a 作业发布已有一两天了 xff0c 之所以今天才编辑这篇博客 xff0c 是因为我也遇到问题了 xff0c 现在以及解决了 xff08 小细节 xff1a 创建功能包之前先编译工作空间确保里面已
  • # gazebo 仿真

    gazebo 仿真 1 给 base link 添加惯性 xff0c 碰撞以及 gazebo 属性 在路径xqrobot description urdf xacro 件夹下新建 件夹 gazebo xff0c 并在 gazebo 件下创建
  • #Gmapping

    Gmapping 开始之前先安装两个功能包 xff0c 命令如下 xff1a sudo apt span class token operator span get install ros span class token operator
  • #navigation

    navigation 1 安装相关依赖 sudo apt span class token operator span get install ros span class token operator span kinetic span
  • # Qt_day1

    Qt day1 1 项目框架 span class token macro property span class token directive hash span span class token directive keyword i
  • ros先订阅后发布 无法收到消息的解决办法

    现象 今天遇到的问题是 使用的是Ros1 在先订阅后发布时 会导致订阅者无法收到订阅的消息 除非在发布者发布后重新订阅 思考 以前使用的是Ros2似乎并不关心订阅和发布的先后顺序 nbsp 似乎都可以收到消息 nbsp nbsp 这个问题后
  • C/C++中关于struct和class类的区别

    struct和class的主要的区别在于两者默认的访问权限有所不同 在不设置类中的成员属性和成员方法的权限时 xff0c struct默认的访问权限是公共权限 xff0c class默认的访问权限是私有权限 补充 xff1a 成员属性和成员
  • C++中STL容器的主要使用及含义

    1 stack栈容器的使用 假如栈中存放的是字符串 xff0c 我们做如下定义 xff1a stack lt string gt ss 设该变量名为ss 其主要用法如下 xff1a ss push a 存入栈中元素a ss top 读取栈顶
  • 电赛备赛记录第一篇(控制部分)

    2022 5 25 九校联赛备赛阶段第一天 联赛小车系统沿用去年国赛使用的树莓派驱动底板与外设 整车情况良好 xff0c 摄像头通信 连接均正常 xff0c 现已拼装完整 复产复工的初步成果为 xff1a 小车可以实现开机自启动的程序运行

随机推荐

  • 数据结构——栈详解

    1 栈 Stack 是一种线性存储结构 xff0c 它具有如下特点 xff1a xff08 1 xff09 栈中的数据元素遵守 先进后出 34 First In Last Out 的原则 xff0c 简称FILO结构 xff08 后进先出的
  • 双目相机标定

    一 运行环境 opencv2 windows vs 二 图像获取 分割 保存 参考博客opencv打开双目摄像头 图像切割保存 scutqq的博客 CSDN博客 双目图像分割 include amp lt opencv2 core core
  • uart1接收不定长度数据和发送:STM32 HAL库串口+DMA+IDLE空闲中断

    DMA增加 xff1a usart1 gpio 默认即可 usart1中断必须打开 在 STM32 中 USART 发送接收有三种基本方式 xff0c 轮询 中断和 DMA 1 轮询方式为堵塞模式 xff0c 使用超时管理机制 它每次接收一
  • 串口、网口等自定义通信协议的问题

    自定义通信协议的问题 一 串口1 通信分为网络通信和串口通信2 协议格式3 协议设计4 代码实现 二 网口1 TCP粘包与拆包 包的划分 出现TCP粘包的原因 粘包与拆包的几种情况 常见的粘包与拆包解决方案 2 为什么UDP没有粘包 xff
  • 如何理解奇偶校验位?

    奇偶校验位提供对传输数据的简单错误 xff08 奇偶校验 xff09 检查 此表描述奇偶校验的类型 奇偶校验类型 xff1a Even 描述 xff1a 数据位加上奇偶校验位产生偶数个1 xfffc 奇偶校验类型 xff1a Mark 描述
  • C语言----隐藏代码文件

    在C语言中 xff0c 常用的文件主要是后缀为 c的源文件以及后缀名为 h的头文件 我们通常使用头文件对函数进行声明 xff0c 使用源文件对具体的函数进行实现 有些时候会由于各种原因需要将函数的功能交给别人使用 xff0c 但是又不想将具
  • c++入门系列(三)之头文件

    1 什么是头文件 xff1f 在C语言家族程序中 xff0c 头文件被大量使用 一般而言 xff0c 每个C 43 43 C程序通常由头文件和定义文件组成 头文件作为一种包含功能的函数 数据接口声明的载体文件 xff0c 主要用于保存程序的
  • std::atomic_thread_fence

    在原子变量的存取上应用不同的memory order可以实现不同的内存序来达到数据同步的目的 xff0c 而在C 43 43 11及之后的标准里 xff0c 除了利用原子操作指定内存序 xff0c 还定义了单独使用 内存栅栏 xff08 s
  • 【数据结构】【期末复习】知识点总结

    算法 线性表 概念明晰 xff1a 随机存取 顺序存取 随机存储和顺序存储 随机存取 顺序存取 随机存储和顺序存储这四个概念是完全不一样的 xff0c 切不可将之混淆 很多人包括我可能认为随机存取就是随机存储 xff0c 顺序存取就是顺序存
  • 【单片机学习】51单片机【定时/计数器】,详细介绍

    51单片机学习 一 先知先会1 CPU时序的有关知识1 1 周期换算2 在学习定时器之前需要明白的3 定时 计数器的工作原理4 51单片机定时器结构 二 定时 计数器的控制1 工作方式寄存器TMOD2 控制寄存器TCON3 定时 计数器的工
  • 【跟着江科大学Stm32】GPIO_LED_流水灯_蜂鸣器

    只要坚持下来了 xff0c 一定会有收获 xff01 一 LED闪烁 span class token macro property span class token directive hash span span class token
  • STM32F103C8T6 PWM驱动舵机(SG90)

    小知识 xff1a 同一个定时器 xff0c 不同通道输出不同输出PWM的特点 对于同一个定时器的不同通道输出PWM xff0c 因为它们是共用一个计数器的 xff0c 所以频率必须一样 xff0c 而占空比由各自的CCR决定 xff0c
  • STM32 PWM周期与频率的计算

    文章目录 STM32 PWM周期与频率的计算频率的计算占空比的计算笔记仅供自学 xff0c 用来回看复习 xff0c 不一定适合你 xff0c 如有错误请指出 STM32 PWM周期与频率的计算 TIM TimeBaseInitTypeDe
  • STM32F103C8T6 实现舵机与电机的控制 2个定时器输出不同频率的PWM

    智能小家居 舵机开门 xff0c 电机做风扇 or 拉窗帘 呼吸灯做提示 xff0c 小OLED屏幕显示当前状态 文章目录 直接上代码main cpwm hpwm cservo hservo cmotor hmotor c笔记仅供自学 xf
  • 【学习记录】Tpro遥控器_暂时取消Tpro的控制权(简易)

    文章目录 按照如下图示配置1 设置好 96 逻辑开关 96 2 选择执行该 96 逻辑开关指令 96 的 96 通道 96 3 配置成功附 xff1a 继电器与R88的接法 按照如下图示配置 1 设置好逻辑开关 2 选择执行该逻辑开关指令的
  • 【Linux】gcc编译工具,断点的设置,gdb调试

    文章目录 注意1 在gcc编译过程中一定要加入选项 96 g 96 xff1b 2 只有在代码处于 96 运行 96 中在 96 暂停 96 状态时才能查看变量值 xff1b 3 设置断点后 xff0c 程序在指定行之前停止 总结主要内容1
  • 【Linux】信号量操作函数

    文章目录 二 实验原理1 semget 函数函数作用 xff1a 参数意义 xff1a 例子 xff1a 2 semop 函数函数作用 xff1a 参数意义 xff1a struct sembuf 结构体定义如下例子 xff1a 再来个完整
  • 【Linux】# 2022 Linux 笔试主要内容 MJ_University

    2022 Linux 笔试主要内容 看前须知道 带 的都是老师复习课上提到的内容 xff0c 但不代表说一定会考哦 xff01 选择题 xff08 20分 xff09 填空题 xff08 20分 xff09 判断题 xff08 10分 xf
  • Ubuntu18.04安装AX210驱动

    Linux Support for Intel Wireless Adapters 从官网可以看到AX210支持的内核版本是5 10 43 如果要在低于5 10的内核版本上安装AX210的驱动的话 xff0c 需要安装以下方法操作 xff1
  • 【Linux】实验四 进程信号通信

    文章目录 一 实验目的二 实验内容三 实验原理1 信号3 1 1 信号的基本概念3 1 2 信号的发送 2 所涉及的系统函数调用3 2 1 fork 3 2 2 kill This is my question 3 2 3 signal 代