task_struct内部存在一个位图结构,用int表示:uint32_t signals;
0000 0000 0000 0000 0000 0000 0000 0000
所谓的发送信号其实就是修改特定进程信号位图的特定比特位
kill options PID
其中,PID是进程的ID,可以是单个进程的ID,也可以是多个进程的ID,用空格分隔
eg:
给ID为1234的进程发送2号信号
kill -2 1234
该处使用的url网络请求的数据。
ps aux | grep 名称关键词
eg:
查找名称与“chrome”相关的后台程序
ps aux | grep chrome
举个例子,在我们不小心写出死循环,或者故意写出死循环以便于使程序持续运行的时候,通常会在命令行输入“Ctrl+C”来停止命令行的无限刷屏,而我们输入的“Ctrl+C”,实际上就是给我们提到的死循环程序发送了2号信号;
下面是两个函数,它们的功能可以让一个程序在接收到2号信号时继续运行,而不是就此退出
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能为“在收到signum号信号的时候执行handler函数”
eg:signal(2,handler) signal(SIGQUIT,handler)
两种写法都可以,signum可以是除了SIGKILL和SIGSTOP以外的任何有效信号
示例代码:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigcb()
{
printf("SIGINT\n");
}
int main()
{
signal(SIGINT,(sighandler_t)sigcb);
while(1)
{
printf("m alive\n");
sleep(2);
}
return 0;
}
运行结果:
按下“Ctrl+C”也会有类似的结果
自己想试一下的话后面可以用“Ctrl+Z”结束这个程序,向它发送9号信号也可以,因为SIGKILL和SIGSTOP这个两个信号不能被系统忽略,也不能被改变默认处理动作
man一下之后可以发现使用文档表示这个函数已经过时了,而且不同系统版本下signal函数的功能也可能不一样
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
也是用来改变进程对于已接收信号做出的行动;
signum可以是任何除了SIGKILL和SIGSTOP以外的有效信号;
如果act不是NULL,则从act安装信号signum的新动作。如果oldact不是NULL,先前的操作保存在oldact中。
所以为了使用这个函数,struct sigaction的结构也必须了解
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
示例代码:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigcb(int m)//为了不报错所以弄成了和结构体中指针相匹配的类型
{
printf("SIGINT\n");
}
int main()
{
struct sigaction m;
m.sa_handler=sigcb;
sigaction(SIGINT,&m,NULL);
while(1)
{
printf("m alive\n");
sleep(1);
}
return 0;
}
运行结果:
这里的“信号集操作函数”指的就是用来操作signal mask的函数;
在 Unix 系统中,每个进程都有一个信号掩码signamask,用于管理它希望阻塞或允许传递的信号。sigprocmask 函数允许程序员操作这个信号掩码,以便选择性地阻塞或解除阻塞特定的信号。
#include <signal.h>
用起来也是事先声明好一个sigset_t类型的信号集``
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
oldset用来存储set的前一个值,也就是说如果oldset为非null,则信号掩码的前一个值存储在oldset中。
如果set为NULL,则信号掩码不变(忽略how),信号掩码的当前值仍然在oldset中返回(如果oldset不是的话)
参数how的参数:
int sigemptyset(sigset_t *set);
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。
int sigaddset (sigset_t *set, int signo);
添加一个signo信号到set这个信号集里面,使signo这个信号变成可以接收到的有效信号
int sigdelset(sigset_t *set, int signo);
把set信号集里面的signo信号删了
int sigfillset(sigset_t *set);
函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系
统支持的所有信号。
示例代码:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main()
{
sigset_t tmp;
sigemptyset(&tmp);
sigaddset(&tmp,2);
sigaddset(&tmp,40);
sigprocmask(SIG_BLOCK,&tmp,NULL);
while(1)
{
printf("m alive\n");
sleep(1);
}
return 0;
}
把2号信号和40号信号都屏蔽了,然后再向test3发送这两个信号,发现什么事也没有发生:
之前那篇讲共享内存的博客相对来说数据比较好,原因可能是我是读了man的使用手册以后按我理解的逻辑顺序讲的,而且我个人认为使用文档里对函数的说明比博客和百度要全面一些
有一些函数因为使用文档太长了所以我只挑了比较重要的部分来讲,如有遗漏欢迎指出
感谢支持