[英]signal handler to terminate the main program and all forks when arrives a double SIGINT
我真的不知道信號處理程序如何工作,尤其是在使用分叉時。 所以我需要做這個練習,但是我無法正常工作。
我的主程序制作了5個fork,每個fork的pid僅打印10條消息。 因此,該程序的目的是,當我通過鍵盤(Ctrl-c)發送SIGINT信號時,它應該打印“單個SIGINT到達”,如果兩個SIGINT在1秒鍾之間到達,則應打印“ double SIGINT到達”並終止整個程序。 因此,當我啟動程序時,它將處理前兩個SIGINT(我將第一個發送的第二個SIGINT發送超過第二個SIGINT),但隨后它不處理單個SIGINT和兩個SIGINT。
所以我對信號非常困惑。 叉繼續標記郵件。 我將相同的處理程序加載到main和fork中,但是當到達double SIGINT時我應該怎么做才能終止所有fork? 我應該在處理程序中調用killl或其他函數來終止它們嗎?
主要功能
/* libraries... */
volatile sig_atomic_t double_sigint = 0;
int64_t time_diff = 0;
int main()
{
int i;
int pid;
sigset_t set;
struct sigaction sa;
/* mask all signals */
/*H*/ if(sigfillset(&set) == -1 )
/*A*/ {perror("sigfillset"); exit(errno);}
/*N*/
/*D*/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1)
/*L*/ {perror("sigfillset"); exit(errno);}
/*E*/
/*R*/ memset(&sa,0,sizeof(sa));
/*B*/
/*L*/ sa.sa_handler = handler;
/*O*/
/*C*/ if(sigaction(SIGINT, &sa, NULL) == -1)
/*K*/ {perror("sigaction"); exit(errno);}
/**/
/**/ /* unmask all signals */
/**/ if( sigemptyset(&set) == -1 )
/**/ {perror("sigepmtyset"); exit(errno);}
/**/
/**/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1 )
/**/ {perror("sigprocmask"); exit(errno);}
for(i=0;i<5;++i)
{
if((pid = fork()) == -1)
{ perror("rec:fork"); exit(errno); }
if(pid == 0)/* figlio */
{
/* SAME HANDLER BLOCK IS HERE */
foo(i);
return;
}
sleep(1);
}
return 0;
}
foo函數
void foo(int i)
{
int k;
for(k=0; k<10; ++k)
{
printf("%d. fork %d. print\n", i, k);
sleep(1);
}
}
信號處理器
void handler (int signum) {
struct timespec sig1;
struct timespec sig2;
if(double_sigint == 0)
{
if(clock_gettime(CLOCK_REALTIME, &sig1))
{ perror("failed to get sig1 time"); exit(errno); }
write(1,"Received single SIGINT\n",18);
double_sigint = 1;
}
else if(double_sigint == 1)
{
if(clock_gettime(CLOCK_REALTIME, &sig2))
{ perror("failed to get sig2 time"); exit(errno); }
time_diff = (sig2.tv_sec - sig1.tv_sec) + (sig2.tv_nsec - sig1.tv_nsec)/1000000000;
if(time_diff < 1)
{
double_sigint = 2;
write(1,"Received double SIGINT\n",18);
_exit(EXIT_FAILURE);
}
else
{
sig1.tv_sec = sig2.tv_sec;
sig1.tv_nsec = sig2.tv_nsec;
write(1,"Received single SIGINT\n",18);
}
}
}
當您收到一個雙SIGINT時,您只用行_exit(EXIT_FAILURE);
殺死父進程_exit(EXIT_FAILURE);
。 您之前創建的fork不會被殺死並繼續運行,它們的父級現在是init進程。
如果要終止所有孩子,則必須手動殺死他們。 也許這篇文章會有所幫助: 如何使子進程在父母退出后死亡
編輯:這不是問題,因為Ctrl + C將SIGINT發送給所有子級(請參閱注釋)。 對我有用的是:
while (1);
因為在父進程終止后不會考慮某些信號)。 在處理程序中,在else子句(double_sigint == 1)中,您正在比較sig2和sig1,但是sig1未初始化。 當處理程序返回時,您第一次給處理程序調用的值消失了。 您可以簡單地為這些變量提供文件作用域。
通過使用局部變量的未初始化值,您將獲得未定義的行為。 如果調用了信號處理程序,並且信號處理堆棧恰好與上一次調用處於同一狀態,則可能工作正常。 例如,如果您兩次發送信號而沒有中間信號,則會發生這種情況。 由於睡眠可能是通過信號實現的,因此很可能堆棧已被修改,因為上一次調用和sig1不是您所期望的。 但是,關於未定義行為的猜測是沒有意義的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.