2011-07-15 46 views
1

更新:這似乎是一個計時問題。在殺死呼叫之前添加一個呼叫進入睡眠狀態可以使所有事情按預期工作。發送和處理克隆線程上的信號

我一直在玩克隆(2),並試圖弄清它是如何工作的。我目前無法將信號發送到克隆進程。我有以下代碼:

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

volatile int keep_going = 1; 

typedef void (*sighandler_t)(int); 

void handler(int sig) { 
    printf("Signal Received\n"); 
    keep_going = 0; 
} 

int thread_main(void* arg) { 
    struct sigaction usr_action; 
    sigset_t block_mask; 
    sigfillset(&block_mask); 
    usr_action.sa_handler = &handler; 
    usr_action.sa_mask = block_mask; 
    usr_action.sa_flags = 0; 
    sigaction(SIGUSR1, &usr_action, NULL); 
    printf("Hello from cloned thread\n"); 
    while(keep_going); 
} 

int main(int argc, char **argv) { 
    void* stack = malloc(4096); 
    int flags = SIGCHLD; 
    int child_tid = clone(&thread_main, stack + 4096, flags, NULL); 
    if (child_tid < 0) { 
     perror("clone"); 
     exit(EXIT_FAILURE); 
    } 
    printf("My pid: %d, child_tid: %d\n", (int) getpid(), (int) child_tid); 
    int kill_ret = kill(child_tid, SIGUSR1); 
    if (kill_ret < 0) { 
     perror("kill"); 
     exit(EXIT_FAILURE); 
    } 
    int status = 0; 
    pid_t returned_pid = waitpid(child_tid, &status, 0); 
    if (returned_pid < 0) { 
     perror("waitpid"); 
     exit(EXIT_FAILURE); 
    } 
    if (WIFEXITED(status)) { 
     printf("exited, status=%d\n", WEXITSTATUS(status)); 
    } else if (WIFSIGNALED(status)) { 
     printf("killed by signal %d\n", WTERMSIG(status)); 
    } else if (WIFSTOPPED(status)) { 
     printf("stopped by signal %d\n", WSTOPSIG(status)); 
    } else if (WIFCONTINUED(status)) { 
     printf("continued\n"); 
    } 
    exit(EXIT_SUCCESS); 
} 

其產生以下的輸出:

My pid: 14101, child_tid: 14102 
killed by signal 10 

孩子明顯打死作爲信號的結果,爲什麼信號處理程序不會被調用?

+0

如果我在殺死的呼叫之前添加一個睡眠呼叫,它就可以工作。看起來這是一個計時問題。 – fido

+0

問題:什麼程序,現在我已經找出了問題,並且不一定有答案給出答案?我應該編輯我的問題並以某種方式關閉它,或者創建我自己的答案並將其提供爲「接受的答案」? – fido

回答

0

首先令人奇怪的是,你沒有得到這樣的信息:它管理設置信號處理程序之前

"Hello from cloned thread\n" 

因此你的孩子胎面被終止。編輯: 我剛剛看到你對睡眠的評論。嘗試添加另一個變量,該變量在執行sigaction時設置。主線程應該被阻塞,直到這個變量沒有被設置。

+0

如果我補充睡眠通話權殺之前(休眠10秒),我得到: 我的PID:14164,child_tid:14165 你好從克隆的線程 信號接收 退出,狀態= 10 因此,它看起來就像在前面的場景中,子線程的信號處理程序尚未安裝。爲了在實際的應用程序中使這更健壯,當初始化完成後,孩子會發信號通知父母,然後父母就可以開始工作。 – fido

2

爲避免競爭狀況,請在撥打clone()之前趕上父母的信號。孩子繼承父母的信號處理程序的副本。如果需要,您可以稍後將其重置爲SIG_DFL。 (另外,如果要在父級上模擬SIG_DFL行爲,則getpid()是異步信號安全的)。

+0

我喜歡那樣。在一遍又一遍地讀完clone(2)manpage幾個小時之後,它變得非常有意義,太糟糕了,我以前沒有弄清楚它:) – fido

1

孩子沒有收到信號,因爲在孩子到達sigaction的電話之前,家長正在發送信號,這就是爲什麼它被殺死。您應該避免以這種方式設置信號處理程序。如果你想這樣做,那麼只要確保父母在等待孩子建立信號處理器。在這種情況下,你應該看到預期的結果。

+0

嗨,阿米特。歡迎來到這個網站!我編輯過,讓你的英語更具地道性。良好的見解! –