Linux的信号

信号的基本概念

信号(signal)是软件中断,是进程之间相互传递消息的一种方法,用于通知进程发生了事件。但是,不能使用信号给进程传递任何数据。 信号产生的原因有很多,在Shell中,可以用killkillall命令发送信号:

kill -信号类型 进程编号

killall -信号类型 进程名

信号的类型(以下仅列出最需要关注的信号类型)

信号名 信号值 默认处理动作 发出信号的原因
SIGINT 2 A 键盘中断 Ctrl+c
SIGKILL 9 AEF 采用 kill -9 进程编号 强制杀死程序
SIGSEGV 11 CEF 无效的内存引用(数组越界、操作空指针和野指针等)
SIGALRM 14 A 由闹钟 alarm() 函数发出的信号
SIGTERM 15 A 采用 kill 进程编号killall 进程名 通知程序
SIGCHLD 17 B 子进程结束信号
其他 ≤64 A 自定义信号

默认处理动作的含义如下:

  • A 终止进程。
  • B 忽略此信号,将该信号丢弃,不做处理。
  • C 终止进程并进行内核映像转储(core dump)。
  • D 停止进程,进入停止状态的程序还能重新继续,一般是在调试的过程中。
  • E 信号不能被捕获。
  • F 信号不能被忽略。

信号的作用

当服务程序运行时,使用信号直接杀掉该进程可能会导致一些资源未能来得及释放从而造成内存占用等一系列问题。如果向服务程序发送一个信号,服务程序收到信号后能够去主动调用退出处理函数,就能使进程有计划地退出。如果向进程发送0信号,可以检测进程是否存活。

发送信号

在程序中,可以使用kill()函数向其他进程发送信号。 函数声明:

1
2
int kill(pid_t pid, int sig);
// kill 函数可以将信号sig发送给指定的进程pid

参数pid的几种情况:

  1. pid>0 将信号传递给进程号为pid的进程
  2. pid=0 将信号传递给和当前进程同进程组的所有进程,常用于父进程给子进程发送信号。(信号发送进程也会收到自己发出的信号
  3. pid=-1 将信号广播给系统内的所有进程。(示例:关机)

参数sig说明:准备发送的信号代码,若sig=0不发出任何信号,但系统会执行错误检查,通常会利用sig值为零来检查某个进程是否仍在运行。 返回值说明:成功执行时,返回0;失败返回-1,errno被设置。

进程终止

正常终止 异常终止
main函数return 调用abort函数中止
exit()函数调用 接收到中止信号
_exit()/Exit()函数调用 在最后一个线程中对取消请求做出响应
最后一个线程从其启动例程中return
在最后一个线程中调用pthread exit()返回

进程终止状态

main()函数中,return的返回值即终止状态,如果没有return语句或调用exit(),那么该进程的终止状态是0。该性质常用于服务程序的调度、日志和监控。在Shell中,程序运行结束时可以使用echo $?查看进程终止的状态。 正常进程终止的三个函数:

1
2
3
4
void exit(int status);
void _exit(int status);
void _Exit(int status);
// status 表示进程终止状态

其中,exit()_Exit()是由ISO C说明的,_exit()是由POSIX说明的。

资源释放的问题

当进程使用return语句返回时,会调用局部对象的析构函数。main()函数中的return还会调用全局对象的析构函数。

exit()表示终止进程,不会调用局部对象的析构函数,只调用全局对象的析构函数。exit()会执行清理工作然后退出,_exit()_Exit()则不执行清理工作直接退出。

进程的终止函数

进程可以使用atexit()函数登记终止函数(最多32个),这些函数将由exit()自动调用。

1
2
int atexit(void (*function)(void));
exit() 调用终止函数的顺序的顺序与登记时相反。进程退出前的收尾工作。
Licensed under CC BY-NC-SA 4.0
热爱可抵岁月漫长,温柔可挡艰难时光。
Nothing but enthusiasm brightens up the endless years.
转载请注明主页网址哦~