信号发送
信号是 Linux 系统响应某些条件而产生的一个事件,接收到该信号的进程会执行相应的操作。 信号的产生有三种方式:
(1)由硬件产生,如从键盘输入 Ctrl+C 可以终止当前进程
(2)由其他进程发送,如可在 shell 进程下,使用命令 kill -信号标号 PID,向指定进程发送信号。
(3)异常,进程异常时会发送信号
在 Ubuntu 终端输入 kill -l,查看所有的信号。
下面是几个常用的函数:
使用规则:
实验 1 代码:在程序中实现:自己给自己发送信号。
sig.c
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <signal.h>
int main(int argc, char const *argv[])
{
//int kill(pid_t pid, int sig);
printf("raise before\n");
raise(9); //自己调用自己
printf("raise after\n");
return 0;
}
编译运行,如下图所示:
实验 2 代码 sig2.c 发送信号:
sig2.c
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
// int kill(pid_t pid, int sig);
pid_t pid;
int sig;
if (argc < 3)
{
printf("请重新输入参数\n");
return -1;
}
// int atoi(const char *nptr);
sig = atoi(argv[2]);
pid = atoi(argv[1]);
kill(pid,sig);
return 0;
}
test.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
while (1)
{
sleep(1);
printf("hello world\n");
}
return 0;
}
编译运行 test,如下图所示,进程会循环打印 hello world
重新打开另一个窗口,编译 sig2.c,然后查看 test 进程的 pid 号,运行测试如下图所示;
实验 3 代码 sig3.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int i;
alarm(3); //相当于定时器
while (1)
{
sleep(1);
i++;
printf("i = %d\n",i);
}
return 0;
}
编译 sig3.c,并运行。如下图所示,设定的时间(3 秒)超过后产生 SIGALARM 信号,默认动作是终 止进程。
信号接收
接收信号:如果要让我们接收信号的进程可以接收到信号,那么这个进程就不能停止。让进程不停止 有三种方法:
while
sleep
pause
方法一:
sig4.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
while (1)
{
sleep(1);
printf("hello world\n");
}
return 0;
}
编译运行结果如下所示,按 ctrl+C 会发送 SIGINT 信号:
方法三
使用 pause()函数,函数详解如下:
pause.c
#include <stdio.h>
#include <unistd.h>
void main(void)
{
printf("pause before\n");
pause();
printf("pause after\n");
}
编译程序并运行,如下图所示:
信号处理
信号是由操作系统来处理的,说明信号的处理在内核态。信号不一定会立即被处理,此时会储存在信 号的信号表中。
处理过程示意图:
由上图中可看出信号有三种处理方式:
1.默认方式(通常是终止进程),
2.忽略,不进行任何操作。
3.捕捉并处理调用信号处理器(回调函数形式)。
实验 1代码实现信号忽略:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main(void)
{
signal(SIGINT,SIG_IGN);
while(1){
printf("wait signal\n");
sleep(1);
}
return 0;
}
编译运行程序,如下图所示,当我们按下 ctrl+C 键的时候,信号被忽略。
实验 2:代码实现采用系统默认方式处理该信号
#include <stdio.h
#include <signal.h>
#include <unistd.h>
int main(void)
{
signal(SIGINT, SIG_DFL);
while (1)
{
printf("wait signal\n");
sleep(1);
}
return 0;
}
编译运行程序,如下图所示,按 ctrl+c
实验 3 代码实现捕获到信号后执行此函数内容
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void myfun(int sig)
{
if(sig == SIGINT)
{
printf("get singnal %d\n",sig);
}
}
int main(int argc, char const *argv[])
{
//signal(int signum, sighandler_t handler)
signal(SIGINT,myfun); // SIG_IGN:忽略信号 SIG_DFL: 系统默认信号
while (1)
{
printf("wait signal\n");
sleep(1);
}
return 0;
}
编译运行程序如下图所示,当我们按下 ctrl+c 时,显示 myfun 函数里面的打印信息。