【问题标题】:catch Ctrl+C in C program [duplicate]在 C 程序中捕获 Ctrl+C [重复]
【发布时间】:2014-12-23 13:57:38
【问题描述】:

我使用以下代码在我的 C 程序中捕获 Ctrl+C

代码

void sig_handler(int signo)
{
    if (signo == SIGINT) 
        exit(EXIT_SUCCESS);
}


void main ()
{
    ......

    if(signal(SIGINT, sig_handler)== SIG_ERR) 
    {
        printf(">>>>>>>>>>>>>>>>>>>>> SIG INT EROOR !!!! sigint=%d ID=%d \n",SIGINT, getpid());
    }
    else 
        printf(">>>>>>>>>>AFTER>>>>>>>>>>> SIG INT  sigint=%d PID=%d \n",SIGINT, getpid());

    char *buf = NULL;
    asprintf(&buf, "%d", getpid());
    write(fd, buf, strlen(buf));
    free(buf);
    uloop_run(); //entering main loop

    ubus_exit();
    uloop_done();

    xml_exit();
    config_exit();

    free(tmp);

    closelog();

    log_message(NAME, L_NOTICE, "exiting\n");

    return 0;
}

我的目的是捕捉 Ctrl + C 但似乎信号处理函数,即sig_handler() 没有运行。

我想知道如何解决?

【问题讨论】:

    标签: c linux operating-system signals openwrt


    【解决方案1】:

    作为iharob answered,您应该为信号添加处理程序。

    但是,您应该仔细阅读 signal(7) 并注意从信号处理程序内部调用 printf 是不合法的(因为 printf 不是 async-signal-safe 函数)。您应该使用write(2) 而不是printf(3)

    这个限制很重要。不要忘记,例如printfmalloc 都可以在任意时刻被打断,但它们不是为此而设计的。

    至少,调用fflush(3) 和/或以\n 结束您的printf 格式字符串;但那仍然是undefined behavior(但你可能“不走运”让它大部分时间做你想做的事)。

    顺便说一句,今天建议使用sigaction(2),而不是“过时”的signal(2)

    在实践中,建议在信号处理程序内部的做法大部分时间是设置一些volatile sigatomic_t 标志(在处理程序外部进行测试),或调用siglongjmp(3)。如果您坚持做其他事情,请确保您仅使用(甚至间接)异步信号安全功能(其中很少,主要是syscalls(2) ....)。特别是,stdio(3)malloc(3) 绝不应该在信号处理程序中使用(这排除了大多数标准 C 函数或大多数库函数)。

    您可能希望在poll(2) 周围有一些event loop(那么您可能会对Linux 特定的signalfd(2)....感兴趣);您应该使用所有警告和调试信息进行编译 (gcc -Wall -Wextra -g)。然后使用gdb 调试器(以及strace(1))来调试你的程序。

    您确定您正在使用的函数(例如uloop_run 等...)没有阻塞或忽略信号吗?你应该strace你的程序来找出答案!

    【讨论】:

    • 我编辑了代码,并从信号处理程序中删除了 printf,但问题仍然存在!
    【解决方案2】:

    您应该使用此函数将处理程序添加到信号中

    sighandler_t signal(int signum, sighandler_t handler);
    

    在你的情况下

    signal(SIGNINT, sig_handler);
    

    还有一点,你的main函数必须返回int,所以void main()是错误的,应该是int main()

    来自OpenWrtuloop_run 函数为SIGINT 安装信号处理程序,因此无法中断它,它会覆盖您的信号处理程序。

    这就是你的信号处理程序永远不会被调用的真正原因。

    程序不会处理信号,直到uloop_run函数退出,这是uloop_run的源代码和相关部分

    static void uloop_setup_signals(bool add)
    {
        struct sigaction s;
        struct sigaction *act, *oldact;
    
        memset(&s, 0, sizeof(struct sigaction));
    
        if (add) {
            s.sa_handler = uloop_handle_sigint;
            s.sa_flags = 0;
            act = &s;
            oldact = &org_sighandler;
        } else {
            act = &org_sighandler;
            oldact = NULL;
        }
    
        sigaction(SIGINT, act, oldact);
    
        if (uloop_handle_sigchld) {
            if (add) {
                //act already points to s, so no need to update pointer
                s.sa_handler = uloop_sigchld;
                oldact = &org_sighandler_child;
            } else {
                act = &org_sighandler_child;
                oldact = NULL;
            }
    
            sigaction(SIGCHLD, act, oldact);
        }
    }
    
    void uloop_run(void)
    {
        struct timeval tv;
    
        /*
        * Handlers are only updated for the first call to uloop_run() (and restored
        * when this call is done).
        */
        if (!uloop_recursive_count++)
            uloop_setup_signals(true);
    
        while(!uloop_cancelled)
        {
            uloop_gettime(&tv);
            uloop_gettime(&tv);
            uloop_run_events(uloop_get_next_timeout(&tv));
        }
    
        if (!--uloop_recursive_count)
            uloop_setup_signals(false);
    }
    

    如您所见,uloop_setup_signals(true);SIGNINT 安装了一个新的信号处理程序,当循环结束时,uloop_setup_signals(false); 被称为恢复以前的信号处理程序。

    所以,这就是原因。

    【讨论】:

    • 在某些系统上,SIGINT 可能不是 2。POSIX 规范化的是 C 名称 SIGINT,而不是它的值!
    • is [while (1) usleep(1000000)] 指令会影响我的 C 代码的下一条指令!!! .
    • @Anis_Stack 这只是在收到SIGINT 之前停止程序的一种方式,为什么不发布程序的其余部分?
    • 什么是uloop_run?我认为它正在覆盖您的信号处理程序。
    • uloop_run 确实添加了信号处理程序,这就是您的程序无法运行的原因。
    猜你喜欢
    • 2015-09-13
    • 2011-01-06
    • 2012-03-17
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多