嵌入式Linux系统编程 — 6.3 kill、raise、alarm、pause函数向进程发送信号

目录

1 kill函数

1.1 kill函数介绍

1.2 示例程序

2  raise函数

2.1 raise函数介绍

2.2 示例程序

3 alarm函数

3.1 alarm函数介绍

3.2 示例程序

4 pause函数

4.1 pause函数介绍

4.2 示例程序


与 kill 命令相类似, Linux 系统提供了 kill()系统调用,一个进程可通过 kill()向另一个进程发送信号;除了 kill()系统调用之外, Linux 系统还提供了库函数 raise(),也可用于实现发送信号的功能。此外,系统调用 alarm()和 pause()函数也可进行发送信号的特殊操作。
 

1 kill函数

1.1 kill函数介绍

kill()系统调用可将信号发送给指定的进程或进程组中的每一个进程, 其函数原型如下所示:

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

int kill(pid_t pid, int sig);
  • pid: 参数 pid 为正数的情况下,用于指定接收此信号的进程 pid;除此之外,参数 pid 也可设置为 0 或-1 以及小于-1 等不同值。
pid取值含义
正数则信号 sig 将发送到 pid 指定的进程
0则将 sig 发送到当前进程的进程组中的每个进程
-1

则将 sig 发送到当前进程有权发送信号的每个进程,但进程 1(init)除外

小于-1

将 sig 发送到 ID 为-pid 的进程组中的每个进程,

进程中将信号发送给另一个进程是需要权限的,并不是可以随便给任何一个进程发送信号,超级用户root 进程可以将信号发送给任何进程,但对于非超级用户(普通用户)进程来说,其基本规则是发送者进程的实际用户 ID 或有效用户 ID 必须等于接收者进程的实际用户 ID 或有效用户 ID。

  • sig: 参数 sig 指定需要发送的信号,也可设置为 0,如果参数 sig 设置为 0 则表示不发送信号,但任执行错误检查,这通常可用于检查参数 pid 指定的进程是否存在。
  • 返回值: 成功返回 0;失败将返回-1,并设置 errno。

1.2 示例程序

示例程序接受一个命令行参数作为要发送信号的进程ID:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[]) 
{
    // 检查参数数量
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // 第一个参数是程序名,第二个参数是我们的进程ID
    pid_t target_pid = (pid_t)strtol(argv[1], NULL, 10);

    // strtol会设置errno,如果转换失败我们需要检查errno
    if (errno == ERANGE || target_pid == (pid_t)-1) {
        perror("Invalid PID");
        exit(EXIT_FAILURE);
    }

    // 要发送的信号,这里我们发送SIGTERM信号
    int signal_to_send = SIGTERM;

    // 使用kill函数发送信号
    if (kill(target_pid, signal_to_send) == -1) {
        // 如果kill调用失败,打印错误消息并退出
        perror("Error sending signal");
        exit(EXIT_FAILURE);
    }

    printf("Signal %d sent to process %d\n", signal_to_send, target_pid);

    return 0;
}
  • 程序首先检查了命令行参数的数量,输入进程ID参数。
  • 使用strtol函数将命令行参数转换为pid_t类型的进程ID。strtol函数尝试将字符串转换为长整数,并允许我们指定基数(这里使用10进制)。检查strtol是否成功转换了字符串。如果转换失败或超出范围,errno会被设置为ERANGE。如果strtol返回(pid_t)-1,并且errno不是ERANGE,这意味着没有发生范围错误,但字符串可能不是一个有效的数字。
  • 使用kill()函数向转换得到的进程ID发送SIGTERM信号。如果信号发送成功,程序将打印一条消息,说明信号已经发送到指定的进程。

程序运行结果如下,可以看到kill没有权限的pid和不存在的pid会报错:

2  raise函数

2.1 raise函数介绍

raise()函数用于发送信号给自己,即发送信号给当前进程。raise()函数原型如下所示:

#include <signal.h>

int raise(int sig)

  • sig指定要发送给当前进程的信号编号。
  • 返回值:如果成功,raise()返回0;如果失败,返回-1并设置errno以指示错误。

 raise()其实等价于:kill(getpid(), sig);

2.2 示例程序

以下是使用raise()函数在当前进程内发送信号的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// 信号处理函数
void signal_handler(int sig) {
    printf("Signal %d caught by process %d\n", sig, getpid());
}

int main() 
{
    // 设置信号处理函数
    struct sigaction sa;
    sa.sa_handler = signal_handler; // 指定信号处理器
    sigemptyset(&sa.sa_mask);       // 初始化信号集,屏蔽信号
    sa.sa_flags = 0;                // 无特殊标志

    // 为SIGUSR1信号设置信号处理函数
    if (sigaction(SIGUSR1, &sa, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    printf("Process %d is running, and will raise SIGUSR1 to itself.\n", getpid());

    // 使用raise发送SIGUSR1信号给自己
    if (raise(SIGUSR1) != 0) {
        perror("raise");
        exit(EXIT_FAILURE);
    }

    return 0;
}
  • 程序首先定义了一个signal_handler函数,用于处理SIGUSR1信号。
  • main函数中,使用sigaction()函数设置了SIGUSR1信号的处理器为signal_handler。然后,我们使用raise(SIGUSR1)向当前进程发送SIGUSR1信号。这将触发signal_handler函数的执行。
  • 如果raise()调用成功,程序将继续执行。如果失败,将打印错误消息并退出。

程序运行结果如下:

3 alarm函数

3.1 alarm函数介绍

alarm函数用于设置一个定时器的系统调用,当定时器到期时,将向进程发送SIGALRM信号。函数原型如下:

#include <unistd.h>

unsigned int alarm(unsigned int seconds);

  • seconds指定定时器到期前的时间,以秒为单位。
  • 返回值alarm()函数返回在调用之前已经设置的任何定时器的剩余时间(以秒为单位)。如果之前没有设置定时器,或者定时器已经到期,返回0。

需要注意的是 alarm 闹钟并不能循环触发,只能触发一次,若想要实现循环触发,可以在SIGALRM 信号处理函数中再次调用 alarm()函数设置定时器。

3.2 示例程序

以下是使用alarm()函数发送信号的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void handle_alarm(int sig) {
    printf("Timer expired, process %d received SIGALRM\n", getpid());
    exit(-1);
}

int main() 
{
    struct sigaction sa;

    // 设置信号处理函数
    sa.sa_handler = handle_alarm;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    if (sigaction(SIGALRM, &sa, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    printf("Process %d will raise SIGALRM in 5 seconds\n", getpid());

    // 设置定时器,5秒后触发SIGALRM
    unsigned int remaining_time = alarm(5);
    if (remaining_time > 0) {
        printf("Previous timer had %u seconds remaining\n", remaining_time);
    }

    // 主循环,等待SIGALRM信号
    while(1) {
        // 这里可以执行其他任务,但在这个例子中,我们只是等待信号
        sleep(1); // 避免CPU占用过高
    }

    return 0;
}
  • 程序定义了一个handle_alarm函数来处理SIGALRM信号。
  • 使用sigaction()设置了SIGALRM的信号处理函数。
  • 使用alarm(5)设置了一个5秒的定时器。定时器到期后,将发送SIGALRM信号给当前进程。
  • 如果之前有设置定时器,alarm()会返回之前定时器的剩余时间。

程序运行结果如下:

4 pause函数

4.1 pause函数介绍

pause()函数一个系统调用,可以使得进程暂停运行、进入休眠状态,直到进程捕获到一个信号为止。pause()函数的原型如下:

#include <unistd.h>

int pause(void);
  • 参数pause()函数不接受任何参数。

  • 返回值pause()函数在正常情况下不会返回,因为它会无限期地挂起执行。只有当进程收到一个信号并且该信号不是通过pause()调用捕获时,它才会返回。如果被信号中断,它返回-1并设置errnoEINTR

4.2 示例程序

 以下是使用pause()函数等待发送信号的示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void handle_signal(int sig) {
    printf("Received signal %d\n", sig);
}

int main() 
{
    struct sigaction sa;

    // 设置信号处理函数
    sa.sa_handler = handle_signal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 为SIGINT设置信号处理函数
    if (sigaction(SIGINT, &sa, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    printf("Process %d is pausing. Send SIGINT to continue.\n", getpid());

    // 挂起进程直到收到信号
    pause();

    printf("Process %d has been resumed.\n", getpid());

    return 0;
}
  • 程序定义了一个handle_signal函数来处理SIGINT信号。
  • 使用sigaction()设置了SIGINT的信号处理函数。
  • 调用pause()使进程挂起,等待接收信号。在这个例子中,我们等待SIGINT信号,这里由通过Ctrl+C触发。
  • 当进程收到SIGINT信号时,pause()返回,handle_signal函数被调用,然后进程继续执行。

程序运行结果如下:

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

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

相关文章

用MySQL+node+vue做一个学生信息管理系统(一):配置项目

先用npm init -y生成配置文件 在项目下新建src文件夹&#xff0c;app.js文件。src目录用来放静态资源文件&#xff0c;app.js是服务器文件&#xff0c;index.js是vue的入口文件 使用npm install express下载express框架 在app.js文件夹开启node服务&#xff0c;监听的端口为…

可视化作品集(01):工业控制领域的大屏

hello&#xff0c;大家好&#xff0c;我是威斯数据&#xff0c;本期开始按照主题来分享可视化大屏/数字孪生项目作品集&#xff0c;大家想看哪些行业的作品&#xff0c;可以在评论区留言。 可视化大屏在工业控制领域可以帮助企业实现生产过程的实时监控、故障预警、生产调度和…

【Windows】Visual Studio Installer下载缓慢解决办法

【Windows】Visual Studio Installer下载缓慢解决办法 1.背景2.分析3.结果 1.背景 使用visual studio在线安装包进行IDE安装&#xff0c;发现下载几乎停滞&#xff0c;网速几乎为零。 经过排查并不是因为实际网络带宽导致。 这里涉及DNS知识&#xff1b; DNS&#xff08;Dom…

Lua、AB包热更新总结

1.AB包热更新 &#xff08;1&#xff09;AB包是一种特定的压缩文件&#xff0c;可以放模型贴图音效等等 &#xff08;2&#xff09;Resources目录下打包时只读 无法修改&#xff1b;而AB包存储的位置是自定义的&#xff0c;能够动态更新&#xff0c;同时可以决定资源包初始的大…

红酒与舞蹈:舞动的味觉艺术

在艺术的海洋中&#xff0c;红酒与舞蹈总是能激起人们心中较温柔的涟漪。红酒以其深邃的色泽、馥郁的香气&#xff0c;诠释着味觉的艺术&#xff1b;而舞蹈&#xff0c;则以优雅的姿态、灵动的步伐&#xff0c;演绎着视觉的盛宴。当红酒遇上舞蹈&#xff0c;一场别开生面的艺术…

pycharm工具回退键调出

pycharm工具调出回退键。 View->Appearance->Toolbar,即可调出 调不出的可以使用快捷键&#xff1a;ctrlalt向左箭头 但是这个快捷键容易和电脑屏幕旋转冲突。可将电脑的快捷键关掉&#xff0c;即可。 ctrlalt向上箭头&#xff1a;将屏幕旋转到正常&#xff08;横向&am…

Monorepo(单体仓库)与 MultiRepo(多仓库): Monorepo 单体仓库开发策略与实践指南

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言1. Monorepo 和 MultiRepo 简介2. 为什么选择 Monorepo&#xff1f; 二、Monorepo 和 MultiRepo 的区别1. 定义和概述2. 各自的优点和缺点3. 适用场景 三、Monorepo 的开发策略1. 版本控制2. 依赖管理3. 构建和发布…

svn忽略上传文件node_modules文件

文章目录 1.点击svn项目右键-》选中svn的属性2. 点击 新建3. 点击其他4. 选择属性 svn:global-ignores5. 输入忽略文件 1.点击svn项目右键-》选中svn的属性 2. 点击 新建 3. 点击其他 4. 选择属性 svn:global-ignores 5. 输入忽略文件

能在网页上快速创建Linux系统的Instantbox

什么是 Instantbox &#xff1f; Instantbox 是一个开源项目&#xff0c;旨在帮助用户在几秒钟内即可获得一个干净、随时可用的 Linux 机器。用户可以选择多种主流的的 Linux 发行版&#xff0c;目前支持 Ubuntu、CentOS、Arch Linux、Debia、Fedora、Alpine 的各个版本。软件基…

华为HCIP Datacom H12-821 卷24

1.单选题 企业大楼有大量员工通常都在上班时在大厅开始接入到公司的WLAN网络,随着每位员工走到各自的工位过程中&#xff0c;每个人的移动端叶通过漫游的方式漫游到各自的网络覆盖区域。为了尽量保证每个终端的IP地址是固定的&#xff0c;建议的做法是? A、配置VLAN Poo…

他们在闲鱼购物开通快手免密支付,支付宝被盗刷上万……

移动支付时代&#xff0c;想必大家都体验过爽到不能再爽&#xff0c;丝滑到不能再丝滑、方便到不能再方便的免密支付吧&#xff01;‍‍‍‍ 小柴前几年也一样&#xff0c;在网络平台消费支付的时候&#xff0c;只要跳出授权免密支付的提醒&#xff0c;通通同意了。 但是被各种…

vue3 在el-input的光标处插入文本

点击文本框下方的按钮&#xff0c;将相应的文本插入光标处的实现&#xff1a; <el-input type"textarea" rows"4" v-model"formula" blur"handleBlur" clearable></el-input><el-button-group class"short_btn&q…

Python28-7.1 降维算法之PCA主成分分析

降维算法是一类数据处理技术&#xff0c;主要用于将高维数据映射到低维空间中&#xff0c;从而减少数据的维度。降维不仅可以减少计算复杂度&#xff0c;提高算法性能&#xff0c;还可以帮助数据可视化。常见的降维算法包括主成分分析&#xff08;PCA&#xff09;、线性判别分析…

冒泡排序写法

正宗的冒泡排序写法&#xff1a; public class BubbleSort {public static void main(String[] args) {int[] a {4,6,5,24,3,7,1};//初始化一个最大角标变量int n a.length-1;//循环轮次for (int i0;i<n;i){//从后向前开始&#xff0c;相邻元素比较大小&#xff0c;小的元…

HTML制作一个时钟走动效果

大家好&#xff0c;今天制作一个时钟走动效果&#xff01; 先看具体效果&#xff1a; 一、以下是一个简单的时钟走动效果的实现&#xff0c;使用了HTML、JavaScript和CSS技术。 <!DOCTYPE html> <html lang"en"> <head> <meta charset"…

【Linux】生物信息学常用基本命令

wget网址用于直接从网上下载某个文件到服务器&#xff0c;当然也可以直接从网上先把东西下到本地然后用filezilla这个软件来传输到服务器上。 当遇到不会的命令时候&#xff0c;可以使用man “不会的命令”来查看这个命令的详细信息。比如我想要看看ls这个命令的详细用法&…

Linux磁盘监控小技巧

作者&#xff1a;田逸&#xff08;formyz&#xff09; 默认情况下&#xff0c;使用Nrpe插件check_disk加选项“-w”与”-c”除了输出我们想监控的磁盘分区外&#xff0c;还输出了一些形如“/dev/shm”不需要监控的项目(如下图所示)&#xff0c;倒对查看起到了一些干扰作用。 从…

解决使用monaco-editor编译器,编译器展示内容没有超过编译器高度,但是出现滚动条问题

前言&#xff1a; 最近在完成项目时&#xff0c;有使用编译器进行在线编辑的功能&#xff0c;就选用了monaco-editor编译器&#xff0c;但是实现功能之后&#xff0c;发现即使在编译器展示的内容没有超过编译器高度的情况下&#xff0c;编译器依旧存在滚动条&#xff0c;会展示…

64、基于去噪卷积神经网络的彩色图像去噪(matlab)

1、基于去噪卷积神经网络的彩色图像去噪的原理及流程 基于去噪卷积神经网络的彩色图像去噪是一种基于深度学习的图像处理技术&#xff0c;可以有效地去除图像中的噪声&#xff0c;提高图像的质量。下面是在Matlab中实现基于去噪卷积神经网络的彩色图像去噪的原理及流程&#x…

01:Linux的基本命令

Linux的基本命令 1、常识1.1、Linux的隐藏文件1.2、绝对路径与相对路径 2、基本命令2.1、ls2.2、cd2.3、pwd / mkdir / mv / touch / cp / rm / cat / rmdir2.4、ln2.5、man2.6、apt-get 本教程是使用的是Ubuntu14.04版本。 1、常识 1.1、Linux的隐藏文件 在Linux中&#xf…