基于命令行程序如何判断自己被终止

本文介绍了如何在命令行程序中捕获和处理中断信号,以优雅地结束程序。在Linux环境下,使用ANSI C的`signal`函数捕获`SIGABRT`、`SIGINT`和`SIGTERM`信号;在Windows下,利用`SetConsoleCtrlHandler`函数来接收和处理Windows控制信号。通过这两个方法,程序可以在被终止前执行必要的清理工作。

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

基于命令行的程序在当今各个操作系统上都应用得非常广泛,但是这些程序没有GUI,所以用户要终止它们时通常都是按"Ctrl+C"或用系统命令直接结束进程,这样可能会造成数据丢失或者一些特殊资源没有释放,因此须要编写一段代码在程序被终止前作一些自己的结束工作。
ANSI C已经提供了一个标准函数signal来捕获命令行的中断信号。
这是该函数在Linux下GCC中的原形:

typedef  void  ( * sighandler_t)( int );
sighandler_t signal(
int  signum, sighandler_t handler);

这是该函数在Microsoft C中的原形:

void  (__cdecl  * signal( int  sig,  void  (__cdecl  * func ) ( int  [,  int  ] ))) ( int );

以上两个函数声明表面上看是乎不同,其实是一样的。

下面介绍该函数的用法。
第一个参数signum为要捕获的信号值,ANSI C定义了以下信号值。

SIGABRT

程序调用了abort函数

SIGFPE

浮点数错误

SIGILL

违例的调用

SIGINT

用户按了CTRL+C

SIGSEGV

违例的内存访问

SIGTERM

用户调用了exit函数

第二个参数handler是一个指向捕获信号回调函数的指针,如果产生了signum指定的信号将执行handler指向的回调函数。
如果singal函数执行成功则返回一个指向上次指定的信号捕获函数的指针,如果执行失败则返回SIG_ERR。
通常要判断程序被终止只须要捕获SIGABRT、SIGINT和SIGTERM这三个信号就行了。

现在来看一个例子:

#include  < stdio.h >
#include 
< singal.h >

int  end  =   0 ;

/**
 * 中断信号处理函数。
 
*/
void  signal_handler(  int  sig )
{
    
switch ( sig )
    {
    
case  SIGINT:
    
case  SIGABRT:
    
case  SIGTERM:
        end 
=   1 //  标记为结束
         break ;
    
default :
        
//  其它信号的处理
         break ;
    }
}

int  main(  int  argc,  char   * argv[] )
{
    
if ( signal(SIGINT,signal_handler)  ==  SIG_ERR )  return   - 1 //  设置处理函数失败
    
    
while ! end )  //  等待结束
    {
#ifdef WIN32
        _sleep( 
1000  );
#
else
        sleep( 
1  );
#endif
        printf( 
" wait... "  );
    }
    
    printf( 
" end. "  );
    
    
return   0 ;
}

将以上代码编译为可执行程序,运行起来然后按Ctrl+C看看有什么效果吧。

但是要注意的是在Windows下命令行也是一个窗口,如果用户直接把命令行窗口关闭的话是不会触发中断信号的,所以Windows API提供了一个函数SetConsoleCtrlHandler用来接收Windows控制信号。
这是该函数的原形:

BOOL WINAPI SetConsoleCtrlHandler( PHANDLER_ROUTINE HandlerRoutine, BOOL Add );

参数HandlerRoutine为接收控制信号的回调函数。参数Add决定是添加还是删除回调函数,这一点和signal函数是不同的,通过SetConsoleCtrlHandler可以添加多个接收控制信号的回调函数。
接收控制信号的回调函数原形:

BOOL WINAPI HandlerRoutine( DWORD dwCtrlType );

参数dwCtrlType为控制信号的类型,是下列值之一。

CTRL_C_EVENT用户按了Ctrl+C。
CTRL_BREAK_EVENT用户按了CTRL+BREAK。
CTRL_CLOSE_EVENT控制台窗口被关闭。
CTRL_LOGOFF_EVENT当前用户注销。
CTRL_SHUTDOWN_EVENT

系统关闭。

如果回调函数返回非0值,系统将不再处理这个控制信号。如果回调函数返回0,系统就将控制信号交给下一个回调函数处理。

SetConsoleCtrlHandler函数和signal的用法大致相同,这里就不多说了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值