signal()函数的使用及小结

本文详细介绍了Linux下signal函数的应用及退出处理方式,包括如何通过signal函数注册信号处理函数,处理不同类型的信号,如SIGINT、SIGTERM等。此外,还探讨了exit与_exit函数的区别及其在进程退出时的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Signal ()函数用法和总结 https://www.cnblogs.com/wuyepeng/p/9790396.html

Linux C++应用程序退出时的事件响应 https://blog.youkuaiyun.com/fk2016/article/details/83381246

void(* signal(int sig,void(* func)(int)))(int);

使用示例1:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <signal.h> 

typedef void (*signal_handler)(int);

void signal_routine(int sig)
{
  switch (sig)
  {
    case 1:
    {
      printf(">>: SIGHUP \r\n");
      break;
    }
    case 2:
    {
      printf(">>: SIGINT \r\n");//"ctrl+c"
      break;      
    }
    case 3:
    {
      printf(">>: SIGQUIT \r\n");//"ctrl+\""
      break;
    }
    case 15:
    {
      printf(">>: SIGTERM \r\n");
      break;
    } 
  }
  printf("killing on exit ! \r\n");
  exit(0);
	return;
}
 
int main(void)
{
	signal_handler sig_handler = signal_routine;
	signal(SIGHUP, sig_handler);
	signal(SIGINT, sig_handler);
	signal(SIGQUIT, sig_handler);
	signal(SIGTERM, sig_handler);
 
	while(true)
	{
		int a = 1 + 1;
	}
	return 0;
}

示例2:

class ExitExpection
{
  public:
    ExitExpection(){};
    ~ExitExpection(){};
};

void signal_routine(int sig)
{
	switch (sig)
	{
    case 1:
    {
      printf(">>: SIGHUP \r\n");
      break;
    }
    case 2:
    {
      printf(">>: SIGINT \r\n");//"ctrl+c"
      break;      
    }
    case 3:
    {
      printf(">>: SIGQUIT \r\n");//"ctrl+\""
      break;
    }
    case 15:
    {
      printf(">>: SIGTERM \r\n");
      break;
    } 
	}
  const ExitExpection e;
  throw(e);
  // printf(">>: killing on exit ! \r\n");
  // exit(0);
}

int main()
{
	signal(SIGHUP, signal_routine);
	signal(SIGINT, signal_routine);
	signal(SIGQUIT, signal_routine);
	signal(SIGTERM, signal_routine);

    try
    {
        /**
         * do something
         * 
         * */
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what() << '\n'<< endl;
    }
    catch(const ExitExpection& e)
    {

        /**
         * do something
         * 
         * */
        printf(">>: killing on exit ! \r\n");
        exit(0);
    }
}

 exit()函数

exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中 

_exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。 

exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是”清理I/O缓冲”。

exit()在结束调用它的进程之前,要进行如下步骤: 

1.调用atexit()注册的函数(出口函数);按ATEXIT注册时相反的顺序调用所有由它注册的函数,这使得我们可以指定在程序终止时执行自己的清理动作.例如,保存程序状态信息于某个文件,解开对共享数据库上的锁等.

2.cleanup();关闭所有打开的流,这将导致写所有被缓冲的输出,删除用TMPFILE函数建立的所有临时文件.

3.最后调用_exit()函数终止进程

exit(0)表示正常退出;传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出,一般都用-1或者1;

exit(0)时,并不会自动执行类的析构函数

 

小结:

1. 对ctrl+c写一signal_handler,使得关闭终端时,抛出自定义异常,在try-catch模块执行class的析构函数,并打印提示信息,最后调用exit(0)函数,  如示例2;

2.signal(SIGCHLD, SIG_IGN)解析 https://blog.youkuaiyun.com/u013246898/article/details/52985739

    处理僵尸进程。忽略SIGCHLD信号,内核将把僵尸进程交由init进程去处理,能够省去大量僵尸进程占用系统资源。 

3.signal(SIGPIPE, SIG_IGN)解析 https://blog.youkuaiyun.com/weixin_33841722/article/details/92183262

          SIGPIPE错误是指,当对端关闭时,而本端并不知情,仍然保持该连接,并向对端写数据,第一次会收到RST,第二次再写则是SIGPIPE信号。你的客户端关闭了,但是服务端仍然在向客户端写数据,因此会产生SIGPIPE信号,该信号默认动作是终止进程。

采用 signal(SIGPIPE,SIG_IGN);忽略该信号。

 

一些常用的Signal :

Signal Description
SIGABRT由调用abort函数产生,进程非正常退出
SIGALRM用alarm函数设置的timer超时或setitimer函数设置的interval timer超时
SIGBUS某种特定的硬件异常,通常由内存访问引起
SIGCANCEL由Solaris Thread Library内部使用,通常不会使用
SIGCHLD 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略
SIGCONT当被stop的进程恢复运行的时候,自动发送
SIGEMT 和实现相关的硬件异常
SIGFPE数学相关的异常,如被0除,浮点溢出,等等
SIGFREEZESolaris专用,Hiberate或者Suspended时候发送
SIGHUP发送给具有Terminal的Controlling Process,当terminal 被disconnect时候发送
SIGILL非法指令异常
SIGINFO BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程
SIGINT由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程
SIGIO异步IO事件
SIGIOT实现相关的硬件异常,一般对应SIGABRT
SIGKILL无法处理和忽略。中止某个进程
SIGLWP由Solaris Thread Libray内部使用
SIGPIPE在reader中止之后写Pipe的时候发送
SIGPOLL 当某个事件发送给Pollable Device的时候发送
SIGPROFSetitimer指定的Profiling Interval Timer所产生
SIGPWR和系统相关。和UPS相关。
SIGQUIT输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程
SIGSEGV非法内存访问
SIGSTKFLTLinux专用,数学协处理器的栈异常
SIGSTOP中止进程。无法处理和忽略。
SIGSYS非法系统调用
SIGTERM请求中止进程,kill命令缺省发送
SIGTHAWSolaris专用,从Suspend恢复时候发送
SIGTRAP实现相关的硬件异常。一般是调试异常
SIGTSTPSuspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程
SIGTTIN当Background Group的进程尝试读取Terminal的时候发送
SIGTTOU当Background Group的进程尝试写Terminal的时候发送
SIGURG当out-of-band data接收的时候可能发送
SIGUSR1 用户自定义signal 1
SIGUSR2用户自定义signal 2
SIGVTALRMsetitimer函数设置的Virtual Interval Timer超时的时候
SIGWAITINGSolaris Thread Library内部实现专用
SIGWINCH当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程
SIGXCPU当CPU时间限制超时的时候
SIGXFSZ进程超过文件大小限制
SIGXRESSolaris专用,进程超过资源限制的时候发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值