单纯的做一下记录笔记
“C/C++” 当在LInux下运行程序时,一般main函数都是使用while循环等待的,如果想退出或结束程序时,只能按Ctrl+C来结束这个进程,但这意味着某些连接是异常断开的,导致服务端无端的一直收到异常信息,所以为了解决程序异常退出问题,捕捉Ctrl+C异常事件,然后在释放使用的东西,让程序正常退出,所以这里就需要用到signal函数
使用平台LInux:
1、signal详解
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
2、Linux下signal信号汇总
SIGHUP 1 /* Hangup (POSIX). */ 终止进程 终端线路挂断
SIGINT 2 /* Interrupt (ANSI). */ 终止进程 中断进程 Ctrl+C
SIGQUIT 3 /* Quit (POSIX). */ 建立CORE文件终止进程,并且生成core文件 Ctrl+\
SIGILL 4 /* Illegal instruction (ANSI). */ 建立CORE文件,非法指令
SIGTRAP 5 /* Trace trap (POSIX). */ 建立CORE文件,跟踪自陷
SIGABRT 6 /* Abort (ANSI). */
SIGIOT 6 /* IOT trap (4.2 BSD). */ 建立CORE文件,执行I/O自陷
SIGBUS 7 /* BUS error (4.2 BSD). */ 建立CORE文件,总线错误
SIGFPE 8 /* Floating-point exception (ANSI). */ 建立CORE文件,浮点异常
SIGKILL 9 /* Kill, unblockable (POSIX). */ 终止进程 杀死进程
SIGUSR1 10 /* User-defined signal 1 (POSIX). */ 终止进程 用户定义信号1
SIGSEGV 11 /* Segmentation violation (ANSI). */ 建立CORE文件,段非法错误
SIGUSR2 12 /* User-defined signal 2 (POSIX). */ 终止进程 用户定义信号2
SIGPIPE 13 /* Broken pipe (POSIX). */ 终止进程 向一个没有读进程的管道写数据
SIGALARM 14 /* Alarm clock (POSIX). */ 终止进程 计时器到时
SIGTERM 15 /* Termination (ANSI). */ 终止进程 软件终止信号
SIGSTKFLT 16 /* Stack fault. */
SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
SIGCHLD 17 /* Child status has changed (POSIX). */ 忽略信号 当子进程停止或退出时通知父进程
SIGCONT 18 /* Continue (POSIX). */ 忽略信号 继续执行一个停止的进程
SIGSTOP 19 /* Stop, unblockable (POSIX). */ 停止进程 非终端来的停止信号
SIGTSTP 20 /* Keyboard stop (POSIX). */ 停止进程 终端来的停止信号 Ctrl+Z
SIGTTIN 21 /* Background read from tty (POSIX). */ 停止进程 后台进程读终端
SIGTTOU 22 /* Background write to tty (POSIX). */ 停止进程 后台进程写终端
SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ 忽略信号 I/O紧急信号
SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ 终止进程 CPU时限超时
SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ 终止进程 文件长度过长
SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ 终止进程 虚拟计时器到时
SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ 终止进程 统计分布图用计时器到时
SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ 忽略信号 窗口大小发生变化
SIGPOLL SIGIO /* Pollable event occurred (System V). */
SIGIO 29 /* I/O now possible (4.2 BSD). */ 忽略信号 描述符上可以进行I/O
SIGPWR 30 /* Power failure restart (System V). */
SIGSYS 31 /* Bad system call. */
SIGUNUSED 31
3、Linux下signal信号表格
信号 | 起源 | 默认行为 | 含义 |
---|---|---|---|
SIGHUP | POSIX | Term | 控制终端挂起 |
SIGINT | ANSI | Term | 键盘输入以终端进程(ctrl + C) |
SIGQUIT | POSIX | Core | 键盘输入使进程退出(Ctrl + \) |
SIGILL | ANSI | Core | 非法指令 |
SIGTRAP | POSIX | Core | 断点陷阱,用于调试 |
SIGABRT | ANSI | Core | 进程调用abort函数时生成该信号 |
SIGIOT | 4.2BSD | Core | 和SIGABRT相同 |
SIGBUS | 4.2BSD | Core | 总线错误,错误内存访问 |
SIGFPE | ANSI | Core | 浮点异常 |
SIGKILL | POSIX | Term | 终止一个进程。该信号不可被捕获或被忽略 |
SIGUSR1 | POSIX | Term | 用户自定义信号之一 |
SIGSEGV | ANSI | Core | 非法内存段使用 |
SIGUSR2 | POSIX | Term | 用户自定义信号二 |
SIGPIPE | POSIX | Term | 往读端关闭的管道或socket链接中写数据 |
SIGALRM | POSIX | Term | 由alarm或settimer设置的实时闹钟超时引起 |
SIGTERM | ANSI | Term | 终止进程。kill命令默认发生的信号就是SIGTERM |
SIGSTKFLT | Linux | Term | 早期的Linux使用该信号来报告数学协处理器栈错误 |
SIGCLD | System V | Ign | 和SIGCHLD相同 |
SIGCHLD | POSIX | Ign | 子进程状态发生变化(退出或暂停) |
SIGCONT | POSIX | Cont | 启动被暂停的进程(Ctrl+Q)。如果目标进程未处于暂停状态,则信号被忽略 |
SIGSTOP | POSIX | Stop | 暂停进程(Ctrl+S)。该信号不可被捕捉或被忽略 |
SIGTSTP | POSIX | Stop | 挂起进程(Ctrl+Z) |
SIGTTIN | POSIX | Stop | 后台进程试图从终端读取输入 |
SIGTTOU | POSIX | Stop | 后台进程试图往终端输出内容 |
SIGURG | 4.3 BSD | Ign | socket连接上接收到紧急数据 |
SIGXCPU | 4.2 BSD | Core | 进程的CPU使用时间超过其软限制 |
SIGXFSZ | 4.2 BSD | Core | 文件尺寸超过其软限制 |
SIGVTALRM | 4.2 BSD | Term | 与SIGALRM类似,不过它只统计本进程用户空间代码的运行时间 |
SIGPROF | 4.2 BSD | Term | 与SIGALRM 类似,它同时统计用户代码和内核的运行时间 |
SIGWINCH | 4.3 BSD | Ign | 终端窗口大小发生变化 |
SIGPOLL | System V | Term | 与SIGIO类似 |
SIGIO | 4.2 BSD | Term | IO就绪,比如socket上发生可读、可写事件。因为TCP服务器可触发SIGIO的条件很多,故而SIGIO无法在TCP服务器中用。SIGIO信号可用在UDP服务器中,但也很少见 |
SIGPWR | System V | Term | 对于UPS的系统,当电池电量过低时,SIGPWR信号被触发 |
SIGSYS | POSIX | Core | 非法系统调用 |
SIGUNUSED | Core | 保留,通常和SIGSYS效果相同 |
4.1、应用实例
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
using namespace std;
bool g_bExit = false;
void Ctrl_c(int)
{
printf("Ctrl + c detected!\n");
g_bExit = true;
}
int main(int argc, char* argv[])
{
signal(SIGINT,&Ctrl_c);
//一直循环不让程序退出
while(!g_bExit)
{
sleep(2);
}
//执行其他东西释放
}
4.2、网上找了一个例子
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
using namespace std;
void sig_handler(int signum)
{
if(0 > signum)
{
fprintf(stderr,"sig_handler param err. [%d]\n",signum);
return;
}
if(SIGINT == signum)
{
printf("Received signal [%s]\n",SIGINT==signum?"SIGINT":"Other");
}
if(SIGQUIT == signum)
{
printf("Received signal [%s]\n",SIGQUIT==signum?"SIGQUIT":"Other");
}
return;
}
int main(int argc,char **argv)
{
printf("Wait for the signal to arrive.\n ");
/*登记信息*/
signal(SIGINT,sig_handler);
signal(SIGQUIT,sig_handler);
pause();
pause();
signal(SIGINT,SIG_IGN);
return 0;
}
有两个信号可以停止进程:SIGTERM和SIGKILL。 SIGTERM 比较友好,进程能捕捉这个信号,根据您的需要来关闭程序。
在关闭程序之前,您可以结束打开的记录文件和完成正在做的任务。在某些情况下,假如进程正在进行作业而且不能中断,那么进程可以忽略这个SIGTERM信号。
对于 SIGKILL 信号,进程是不能忽略的。这是一个 “我不管您在做什么,立刻停止”的信号。假如您发送SIGKILL信号给进程,Linux就将进程停止在那里。
函数 | 说明 |
---|---|
sigaddset | 将信号signo 加入到信号集合之中; |
sigdelset | 将信号从信号集合中删除; |
sigemptyset | 函数初始化信号集合set,将set 设置为空; |
sigfillset | 也初始化信号集合,只是将信号集合设置为所有信号的集合; |