簡體   English   中英

當孩子有一個處理程序時,父 shell 沒有得到 SIGINT

[英]parent shell not getting SIGINT when child has a handler

當您按 Ctrl-C 時,前台進程會收到 SIGINT:

$ bash -c 'sleep 100; echo program died'
^C
$ echo $?
130

但是,如果程序安裝了 SIGINT 處理程序,則父程序不會收到信號。 為什么?

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

void sig_int(int sig_num)
{
    exit(1);
}

static struct sigaction sigact = { .sa_handler=sig_int };

int main(int argc, char *argv[])
{
    sigaction(SIGINT,&sigact,NULL);
    sleep(100);
    return 0;
}

bash 沒有死:

$ bash -c './a.out; echo program died'
^Cprogram died

Bash not trapping interrupts during rsync/subshel​​l exec statements 相關,但所有答案都有解決方法。

如果不是直接從終端發送,shell 將忽略 SIGINT

這個長解釋什么是細節發生。 在這里,我將嘗試總結最重要的概念並提出一個可行的解決方案。


事實證明,如果SIGINT不是直接從終端發送的(通過按CTRL-C ),則 shell 被編程為忽略SIGINT 如果子進程攔截了它,那么它必須通過使用SIGINT顯式殺死自己來退出,引用帖子:

“如果你沒有捕捉到 SIGINT,系統會自動為你做正確的事情:你的程序退出,調用程序在等待你退出后獲得正確的“I-exited-on-SIGINT”狀態。

但是一旦你捕捉到 SIGINT,你必須在你的 SIGINT 處理程序中進行任何清理之后采取正確的退出方式。

決定 SIGINT 是否用於退出/中止目的,因此調用該程序的 shellscript 應該停止。 希望這是顯而易見的。 如果您只需要對 SIGINT 進行一些清理,然后立即退出,那么答案是“是”。

如果是這樣,您必須通過以“I-exited-on-SIGINT”狀態退出來告訴調用程序有關它的信息。

除了用 SIGINT 信號殺死自己之外,沒有其他方法可以做到這一點。 通過將 SIGINT 處理程序重置為 SIG_DFL 來實現,然后向自己發送信號。

 void sigint_handler(int sig) { [do some cleanup] signal(SIGINT, SIG_DFL); kill(getpid(), SIGINT); }

信號處理程序

這是攔截信號並正確殺死自己的處理程序的工作版本(因此它不會打印“程序死亡”)。 OTOH,如果您發送不同的信號,處理程序將運行exit函數,您將再次在屏幕上看到“程序已死”。

void sig_int(int sig_num)
{
    if (sig_num == SIGINT) {
        printf("received SIGINT\n");
        signal(SIGINT, SIG_DFL);
        kill(getpid(), SIGINT);
    } else {
        exit(1);
    }
}

static struct sigaction sigact = { .sa_handler=sig_int };

int main(int argc, char *argv[])
{
    sigaction(SIGINT,&sigact,NULL);
    printf("go to sleep\n");
    sleep(3);
    printf("awaken\n");
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM