我有一個用戶定義的信號處理程序的父進程。每當收到一個信號,我設置一個全局變量,並在我的主循環中檢查是否在每次輸入處理之前收到信號。當進程在waitpid中等待時如何處理信號?
我產生一個進程來處理用戶輸入並使用waitpid來收集孩子的等待狀態。同時如果父進程收到用戶定義的信號,如何有效地處理它?從我的應用程序
#include <stdio.h>
#include <signal.h>
volatile sig_atomic_t g_signal_number =0;
void sig_hup_handler()
{
g_signal_number = SIGHUP;
}
void do_process_cleanup() {
//Execute
}
int execute_user_input(char *str)
{
pid_t cpid,w;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { //Child may take 10-20 second to process the string.
execute_command(str);
_exit(0);
} else {
w = waitpid(cpid, &status, 0);
}
}
main()
{
char str[1024];
signal(SIGHUP, sig_int_handler);
while(1) {
if(g_signal_number)
{
do_process_cleanup();
break;
}
get_user_input(str);
if(!strcmp(str,"end"))
break;
execute_user_input(str);
}
exit(0;)
}
最小化的代碼剪斷我嘗試下面的代碼來解決這個問題。有人可以提出更好的方法來處理這個問題嗎?
while (1) {
int ret = waitpid(cpid, &status, WNOHANG);
if(ret > 0)
break;
if(ret < 0)
if(errno == EINTR)
continue;
if(g_signal_number) // break the loop if signal recieved
break
sleep(1);
}
也嘗試過SA_RESTART標誌,但它沒有在我的Linux風格的waitpid系統調用工作。
int main() {
:
sa.sa_handler = sig_hup;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
:
while(1) {
ret=waitpid(child_pid, &status, 0);
/*
*if waipid returns -1 and errno is set to
*EINTR and g_signum is set,
*break the loop.
*/
if(ret == -1 && errno == EINTR && g_signum) {
printf("signal is set, so break the loop\n");
break;
}
printf("waitpid restart...\n");
}
從strace輸出我可以看到,在發送SIGHUP到PID 17618之後,waitpid也不會中斷。
-bash-4.1$ strace -p 17618
Process 17618 attached
wait4(17619, 0x7ffc4a2e2c34, 0, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=26521, si_uid=332691} ---
rt_sigreturn() = 61
wait4(17619,
環境:一個RedHat般的發行版,2.6.39內核
更新
如果有人打在未來這個問題請參考答案爲Why doesn't Linux accept() return EINTR?
失去'WNOHANG'和'睡眠()' 。讓'waitpid()'塊直到孩子死亡或你得到信號。 'while(waitpid(cpid,&status,0)> 0 || errno == EINTR){if(g_signal_number);打破; '也許。 –
@JonathanLeffler。我將quesiton.modified的SIGINT信號編輯爲SIGHUP。如果父進程收到SIGHUP,waidpid會將errno設置爲EINTR? –
'EINTR'表示收到一個信號(任何信號),而不是特意接收到'SIGINT'。 –