Linux进程通信:信号相关函数

news/2024/12/2 21:35:32/

1. kill函数

#include<sys/types.h>
#include<signal.h>int kill(pid_t pid, int sig);
/*
功能:给进程pid发送信号sig
参数:pid:取值有4种情况:> 0:将sig信号发送给进程号为pid的进程;= 0:将sig信号发送给当前进程组中的所有进程;= -1:将sig信号发送给系统内的所有进程;< -1:将sig信号发送给进程组号为pid绝对值的进程组中的所有进程。sig:信号。推荐使用信号宏。
返回值:成功:0;失败:-1
*/

a)root权限用户可给任意用户发信号,普通用户不可给root权限用户发信号;

b)普通用户不允许:kill -9 root用户进程的pid; 普通用户也不允许向其他普通用户发送信号终止其进程,只能向自己创建的进程发送信号;普通用户只能给自己的进程发送信号。

kill函数示例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<signal.h>
#include<unistd.h>int main(int argc, const char* argv[]) {pid_t pid = -1;int ret = -1;// 创建一个子进程pid = fork();if (-1 == pid) {perror("fork");return 1;}// 父进程杀死子进程if (pid > 0) {  // 父进程sleep(3);ret = kill(pid, SIGTERM);if (-1 == ret) {perror("kill");return 1;}printf("子进程被杀死!\n");} else {  // 子进程while (1) {printf("子进程运行中...\n");sleep(1);}exit(0);}return 0;
}

运行结果:


2. raise函数

#include<signal.h>int raise(int sig);
/*
功能:当前进程给自己发送信号sig,相当于kill(getpid(), sig);
参数:sig:信号宏;
返回值:成功:0失败:非0
*/

raise函数示例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<signal.h>
#include<unistd.h>int main(int argc, const char* argv[]) {int i = 4;while (1) {printf("进程%d自杀倒计时: %d\n", getpid(), i);sleep(1);if (0== --i) {printf("进程%d杀死自己.\n", getpid());raise(SIGTERM);}}return 0;
}

运行结果:


 3. abort函数

#include<stdlib.h>void abort(void);
/*
功能:给自己发送异常终止信号,即6号信号SIGABTR,并产生core文件。等价于kill(getpid(), SIGABRT);
*/

abort函数示例:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>int main(int argc, const char* argv[]) {int i = 3;while (1) {printf("终止倒计时:%d\n", i--);sleep(1);if (0 == i) {printf("进程终止!\n");abort();}}return 0;
}

运行结果:


4. alarm函数

定时器

#include<unistd.h>unsigned int alarm(unsigned int seconds);
/*
功能:设置定时器:指定seconds后,内核给当前进程发送14号信号SIGALRM信号,进程收到该信号,默认终止进程。每个进程有且只有唯一的定时器。
参数:seconds:定时时间,单位s;为0时则表示取消定时器,并返回旧闹钟剩余秒数。
返回值:0或剩余秒数。
*/

注意:alarm函数与调用进程状态无关。进程处于任何状态(退出除外),alarm都会计时。

alarm函数示例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>int main(int argc, const char* argv[]) {unsigned int ret = 0;ret = alarm(5);sleep(3); // 进程的sleep状态不会影响闹钟的计时ret = alarm(4); // 覆盖之前的闹钟,重新计时/* 结果为2. 第一次计时5秒,sleep了3秒,执行到第二个闹钟时,第一次闹钟剩余2s*/printf("上次闹钟剩下的时间:%u\n", ret);getchar();return 0;
}

运行结果:

 前后总共计时7s


5. setitimer函数

多功能定时器

#include<sys/time.h>int setitimer(int which, const struct itimerval* new_value, struct itimerval* old_value);
/*
功能:设置定时器。可替代alarm,精度μs。可实现周期定时。
参数:which:定时方式:a) 自然定时:ITIMER_REAL(14号信号,SIGALRM),计算自然时间,默认终止进程;b) 虚拟空间计时(用户空间):ITIMER_VIRTUAL(26号信号,SIGVTALRM),只计算占CPU时间;c) 运行时计时(用户+内核):ITIMER_PROF(27号信号,SIGPROF),计算占用CPU+系统调用时间;new_value:超时时间;itimerval.it_value:第一次执行function延迟的秒数;itimerval.it_interval:以后执行function的时间间隔old_value:存放旧的timeout值,一般为NULL
返回值:成功:0;失败:-1
*/struct itimerval {struct timerval it_value;    // 闹钟触发时间struct timerval it_interval; // 闹钟触发周期
}struct timeval {long tv_sec;   // 秒long tv_usec;  // 微秒
}

setitimer示例:

#include<stdio.h>
#include<sys/time.h>
#include<stdlib.h>
#include<string.h>int main(int argc, const char* argv[]) {int ret = -1;struct itimerval tmo;// 第一次触发时间: 3stmo.it_value.tv_sec = 3;tmo.it_value.tv_usec = 0;// 触发周期: 2s一次。 此处无效果,需结合后面的信号捕捉使用。tmo.it_interval.tv_sec = 2;tmo.it_interval.tv_usec = 0;// 设置定时器, 默认动作:终止进程ret = setitimer(ITIMER_REAL, &tmo, NULL);if (-1 == ret) {perror("setitimer");return 1;}printf("按下任意键继续\n");getchar();return 0;
}

运行结果:


6. signal函数

注册信号处理函数。

注:由于历史原因,signal函数在不同版本的类Unix系统中含义不同,应避免使用signal函数。

#include<signal.h>typedef void(*sighandler_t)(int);
/*
函数指针。
名字:sighandler_t,返回值:void,形参:一个int类型;
*/sighandler_t signal(int signum, sighandler_t handler);
/*
功能:注册信号处理函数:收到signum信号,则执行handler函数。不可用于SIGKILL、SIGSTOP信号。
参数:signum:信号编号,建议写信号的宏;handler:3中取值情况:SIG_IGN:忽略该信号;SIG_DFL:执行默认处理方式;回调函数名:自定义处理方式;回调函数定义如下:void func(int signo) {// signo为触发的信号,为signal函数的第一个参数}
返回值:成功:第一次返回NULL,下一次返回此信号上次注册的信号处理函数的地址;若需要使用此返回值,则必须在前面声明此函数的指针类型。失败:SIG_ERR
*/

signal示例1:

捕捉Ctrl+c、Ctrl+\信号,并自定义各自的处理方式。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>void func0(int signum) {printf("捕捉到信号:%d\n", signum);
}void func1(int signum) {printf("捕捉到信号:%d\n", signum);
}int main(int argc, const char* argv[]) {/*注册信号处理函数。*/// SIGINT: Ctrl + csignal(SIGINT, func0); // 处理异步信号/*SIGQUIT: Ctrl + \*/signal(SIGQUIT, func1);while (1) {getchar();}return 0;
}

运行结果:

signal示例2:

捕捉setitimer信号,修改它默认终止进程的行为。

#include<stdio.h>
#include<sys/time.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>void func(int signum) {printf("捕捉到SIGALRM信号.\n");
}int main(int argc, const char* argv[]) {int ret = -1;struct itimerval tmo;// 第一次触发时间: 3stmo.it_value.tv_sec = 3;tmo.it_value.tv_usec = 0;// 触发周期: 2s一次。 此处无效果,需结合后面的信号捕捉使用。tmo.it_interval.tv_sec = 2;tmo.it_interval.tv_usec = 0;// 捕捉信号SIGALRM,修改它的默认处行为。signal(SIGALRM, func);// 设置定时器, 默认动作:终止进程ret = setitimer(ITIMER_REAL, &tmo, NULL);if (-1 == ret) {perror("setitimer");return 1;}printf("按下任意键继续\n");getchar();return 0;
}

运行结果:


7.  sigaction函数

改变指定信号的处理方式,功能类似于signal。

#include<signal.h>int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
/*
功能:修改或检查signum信号的处理方式。
参数:signum:要操作的信号;act:信号的新处理方式;传入参数;oldact:信号原先的处理方式;传出参数;若act非空,则将信号原处理方式变为act;若oldact非空,则将先前的处理方式存入oldact。
返回值:成功:0失败:-1
*/struct sigaction {void(*sa_handler)(int);                      // 旧的信号处理函数指针void(*sa_sigaction)(int, siginfo_t*, void*); // 新的信号处理函数指针sigset_t sa_mask;         // 阻塞信号集int sa_flags;             // 信号处理方式void(*sa_restorer)(void); // 已弃用
}
/*
(1) sa_handler、sa_sigaction:信号处理函数指针,与signal函数中的函数指针用法一样,根据情况给两者之一赋值。a) SIG_IGN:忽略该信号b) SIG_DFL:执行默认处理方式c) 回调函数名:自定义处理方式
(2) sa_mask:阻塞信号集。信号处理函数执行过程中,临时屏蔽指定信号。
(3) sa_flags:指定信号处理行为,通常设置为0(使用旧的信号处理函数). 也可是以下值的"按位或"组合SA_NOCLDSTOP:使父进程在其子进程暂停或继续运行时不会收到SIGCHLD;SA_NOCLDWAIT:使父进程在其子进程退出时不会收到SIGCHLD信号,此时子进程也不会成为僵尸进程;SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能收到该信号;SA_RESETHAND:信号处理之后重新设置为默认的处理方式;SA_SIGINFO:使用sa_sigaction成员而不是sa_handler作为信号处理函数;SA_RESTART:使被信号打断的系统调用自动重新发起(已废弃);
*/void(*sa_sigaction)(int, siginfo_t*, void*);
/*
功能:新的信号处理函数指针,
参数:signum:信号编号;info:记录信号发送进程信息的结构体;context:赋给指向ucontext_t类型的一个对象指针,以引用在传递信号是被中断的接收进程或线程的上下文。
*/

sigaction示例1:

旧的信号处理函数:

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>// 信号处理函数
void func(int signum) {printf("捕捉到信号%d.\n", signum);
}int main(int argc, const char* argv[]) {int ret = -1;struct sigaction act;act.sa_handler = func;  // 自定义旧的信号处理函数act.sa_flags = 0;  // 使用旧的信号处理函数ret = sigaction(SIGINT, &act, NULL);if (-1 == ret) {perror("sigaction");return 1;}printf("按下任意键继续...\n");getchar();return 0;
}

运行结果:

 

sigaction示例2:

新的信号处理函数:

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>// 信号处理函数
void func(int signum, siginfo_t* info, void* context) {printf("捕捉到信号%d.\n", signum);
}int main(int argc, const char* argv[]) {int ret = -1;struct sigaction act;act.sa_sigaction = func;  // 自定义新的信号处理函数act.sa_flags = SA_SIGINFO;  // 使用新的信号处理函数ret = sigaction(SIGINT, &act, NULL);if (-1 == ret) {perror("sigaction");return 1;}printf("按下任意键继续...\n");getchar();return 0;
}

运行结果:

 


8. sigqueue函数

#include<signal.h>int sigqueue(pid_t pid, int sig, const union sigval value);
/*
功能:给指定进程发送信号。
参数:pid:进程号;sig:信号;value:通过信号传递的参数。union sigval {union sigval {int sival_int;void* sival_ptr;}}
返回值:成功:0失败:-1
*/

http://www.ppmy.cn/news/56071.html

相关文章

03-Vue技术栈之生命周期

目录 1、什么是生命周期2、分析生命周期2.1 生命周期钩子函数2.2 生命周期钩子函数的作用2.3 生命周期钩子函数图例2.4 生命周期钩子函数的应用 3、生命周期总结 1、什么是生命周期 又名&#xff1a;生命周期回调函数、生命周期函数、生命周期钩子。是什么&#xff1a;Vue在关…

iOS可视化动态绘制八种排序过程

一、可视化解决方案综述 1.交互UI综述 在本篇博客的第一部分我们先来整体的看一下我们Demo的功能。下方就是我们今天博客中的Demo的交互示意图。上方的输入框可以输入要排序元素的个数&#xff0c;下方输入的是300。程序会根据你输入的个数来随机生成数据&#xff0c;你输入30…

数字化转型导师坚鹏:BLM企业数字化转型战略

BLM企业数字化转型战略 ——以BLM模型为核心&#xff0c;实现知行果合一 课程背景&#xff1a; 很多企业存在以下问题&#xff1a; 不知道企业如何制定数字化转型战略&#xff1f; 不清楚其它企业数字化转型战略是如何制定的&#xff1f; 不知道其它企业数字化转型战略…

嵌入式Sqlite数据库【基本语法、Sqlite-JDBC、嵌入到Java程序】

目录 前言 基本介绍 Sqlite 对比 MySQL 字段类型 语法 创建表 插入数据 更新数据 查询数据 删除数据 查看建表语句 Sqlite-JDBC 嵌入到Java程序 前言 最近在用JavaFX做一个桌面软件需要用到数据库&#xff0c;但MySQL这种数据库明显只能本地访问&#xff0c;把软…

【物联网】物1— 初步认识MQTT、连接到MQTT服务端

目录 一、MQTT是什么 二、MQTT的版本 两者之间的关系&#xff1a; ​三、MQTT工作的基本原理 3.1、概念 MQTT客户端&#xff1a; MQTT服务端&#xff1a; MQTT主题&#xff1a; 3.2、MQTT订阅/发布主题的特点 相互可独立性&#xff1a; 空间可分离&#xff1a; 时间…

推荐一款网站内链爬取python脚本

目标 使用 web-tools 提供的webSpider来爬取网站内链&#xff0c;并且将其导出。 webSpider介绍&#xff1a; 官网链接&#xff1a;https://web-tools.cn/web-spider 仓库地址&#xff1a;https://github.com/duerhong/web-spider Web Spider 专门用于爬取网站内链&#xf…

面试题复习

闭包造成的内存泄漏如何回收&#xff1f; 方法一&#xff1a;将闭包内部使用的外部变量改为局部变量&#xff0c;让垃圾回收机制自动回收。 function foo() {let bar bar;return function() {let localBar bar; // 将 bar 变量作为局部变量使用console.log(localBar);} }le…

C#开发的OpenRA游戏的创建基地工程车

C#开发的OpenRA游戏的创建基地工程车 OpenRA游戏里,如果不是任务性的目标,一般都需要创建一个基地工程车。 因为这个游戏所有的起点,就是一台基地工程车,只有建立基地, 才能创建其它所有物品,比如发电工厂、炼矿工厂、兵工厂, 只有这样之后,才能去制造各个兵种,才能制…