C中的信号处理

Posted

技术标签:

【中文标题】C中的信号处理【英文标题】:Signal Handling in C 【发布时间】:2011-01-29 21:54:11 【问题描述】:

如何在 C 中实现 Ctrl-C 和 Ctrl-D 的信号处理......所以如果按下 Ctrl-C,那么程序将忽略并尝试再次从用户那里获取输入......如果 Ctrl -D 被按下然后程序将终止...

我的程序如下:

int main()
 char msg[400];

 while(1)
   printf("Enter: ");
   fgets(msg,400,stdin);
   printf("%s\n",msg); 
 

谢谢,

戴夫

【问题讨论】:

我不会推荐这个。在很少的情况下,我能想到让程序覆盖 Ctrl-C 的 kill 功能是一个好主意 - 远程连接工具,如 SSH 就是其中之一。 这只是为了了解如何处理信号 任何类型的解释程序都应该捕获 ctrl-C 以中止托管程序,如果它正在运行。 【参考方案1】:

在处理 POSIX 信号时,您可以使用两种方法。首先,简单(但已弃用)的方式,signal()。其次,更优雅、更现代但更复杂的方式,sigaction()。请使用 sigaction() ,除非您发现它在您需要工作的某些平台上不可用。

glibc 手册的This chapter 解释了两者之间的差异,并提供了如何使用两者的很好的示例代码。它还列出了可以处理的信号,建议如何处理它们应该,并更深入地了解如何判断任何给定信号当前是(或不是)存在 处理。这比我想在这里粘贴到答案中的代码要多得多,因此是链接。

真的值得花一两个小时阅读链接并完成示例。信号处理(尤其是在守护程序中)非常重要。一个好的程序应该处理所有可以处理的致命信号(即 SIGHUP)并明确忽略它可能未使用的信号(即 SIGUSR1 / SIGUSR2)。

研究正常信号和实时信号之间的差异也没有什么坏处,至少要了解内核如何合并先验而不是后者。

一旦你完成它,你可能会倾向于编写一组易于修改的函数来处理你的信号并一遍又一遍地重用该代码。

很抱歉没有提供快速而肮脏的代码 sn-p 来向您展示如何解决您的迫切需求,但这不是一个快速而肮脏的话题:)

【讨论】:

【参考方案2】:

首先,Ctrl+D 是一个无法捕获的 EOF 指示符,当程序等待输入时,按 Ctrl+D 表示文件结束,并且不希望再有输入。另一方面,使用 Ctrl+C 来终止程序 - 即 SIGINT,可以通过这样做来捕获:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>

static void signal_handler(int);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);

struct sigaction sigact;
char *progname;

int main(int argc, char **argv)
    char *s;
    progname = *(argv);
    atexit(cleanup);
    init_signals();
    // do the work
    exit(0);


void init_signals(void)
    sigact.sa_handler = signal_handler;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGINT, &sigact, (struct sigaction *)NULL);


static void signal_handler(int sig)
    if (sig == SIGINT) panic("Caught signal for Ctrl+C\n");


void panic(const char *fmt, ...)
    char buf[50];
    va_list argptr;
    va_start(argptr, fmt);
    vsprintf(buf, fmt, argptr);
    va_end(argptr);
    fprintf(stderr, buf);
    exit(-1);


void cleanup(void)
    sigemptyset(&sigact.sa_mask);
    /* Do any cleaning up chores here */

【讨论】:

SIG_IGN 处理程序可以很好地满足 OP 的需求。 为什么sigact是一个全局变量?为什么清理会摆弄它;您必须再次调用 sigaction() 才能更改 sigact 以影响程序的行为方式。 @JonathanLeffler :你能不能更好地解释一下为什么声明 sigact global 不是一个好主意,好吗?我想明白这一点。谢谢。 @Kyrol:不需要它是一个全局变量;它完全可以是函数中的局部变量,因为它只在函数内部使用。当调用sigaction() 时,内核会从结构中复制它需要的信息;之后您不需要保留该值。【参考方案3】:

在您的示例中,您似乎根本不需要 CTRL-C handlind。 “信号(SIGINT,SIG_IGN)”对您来说似乎已经足够了,除非您的应用程序必须处理来自其他来源的 SIGINT。 CTRL-D 通常不生成信号,它只是传达 EOF 条件。 您通常可以通过使用termios library(也称为here)来控制终端的行为(我们说的是控制台输入,不是吗?)。您可以启用、重新定义或禁用“中断”字符 (CTRL-C)、EOF 和许多其他字符(XON、XOFF、调制解调器控制...)

问候

【讨论】:

【参考方案4】:

这是一个Ctrl+c信号处理程序

信号函数的语法是:signal(signal name, function name);

#include<stdio.h>
#include<signal.h>  // for handling signal 

void signal_handler() 

    printf("Signal Handled here\n");


main() 

    printf("In main function..\n");

    // SIGINT is signal name create  when Ctrl+c will pressed 
    signal(SIGINT,signal_handler);  

    sleep(15);

    printf("In main after called from signal_handle \n");


【讨论】:

signal() 已弃用,应尽可能避免使用,几乎所有现代平台(除了一些嵌入式)都提供sigaction() @TimPost signal() 从未被弃用。它提供的控制少于sigaction()。但这与弃用不同。【参考方案5】:
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
void signal_catch()

    printf("hi,Your signal catched Here");  

int main()

    signal(SIGINT,signal_catch);
//press ctrl+c
    sleep(10);
    return 0;
//end main

//if you want to simply ignore ctrl+c interrupt use following code in main

int main()

    signal(SIGINT,SIG_IGN);
    sleep(100);
    return 0;
//end main  
//this program  wont accept ctrl+c interrupt for 100 seconds. 

【讨论】:

以上是关于C中的信号处理的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp C,SIGINT,SIGALRM,SIGHUP中的Unix信号处理示例......

C中的信号量数组和相互赋值

是否为 C++11 中的信号中断(或信号处理程序)定义了 std::this_thread::sleep_for 行为?

C/C++ 中的跨平台通用文本处理

急求 程序代码 c/c++ 操作系统中的 处理机调度算法

C中的预编译宏定义