2015-03-18 138 views
1

我想寫一個具有一些進程數的C程序。其中一個發送一個SIGRTMIN和SIGRTMAX範圍內的隨機信號給所有其他進程,但是我希望這個信號在主進程中被忽略。我使用全局變量讓隨機信號通過SIG_IGN忽略。它看起來沒有幫助,因爲當想要忽略第一個隨機信號時,主要停止使用實時信號。與信號進程通信

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <time.h> 

volatile sig_atomic_t disarming_signal = 0; 

void disarming_handler (int sig) { 
    disarming_signal = sig; 
    fprintf(stderr,"signal %d is handeled", disarming_signal); 
} 
int rand_range(int min_n, int max_n){ 
    int rand_n = rand() % (max_n - min_n) + min_n; 
    return rand_n; 
} 
int sethandler (void (*f)(int), int sigNo) { 
    struct sigaction act; 
memset(&act, 0, sizeof(struct sigaction)); 
act.sa_handler = f; 
    if (-1==sigaction(sigNo, &act, NULL)) 
     return -1; 
return 0; 
} 
void sigchld_handler(int sig){ 
pid_t pid; 
for(;;){ 
    pid=waitpid(0, NULL, WNOHANG); 
    if(pid==0) return; 
    if(pid<=0) { 
     if(errno==ECHILD) return; 
     perror("waitpid:"); 
     exit(EXIT_FAILURE); 
    } 
} 
} 

void usage(){ 
fprintf(stderr,"USAGE: sappartherroryst n\n"); 
fprintf(stderr,"n - number of Therrorysts\n"); 
} 

void therroryst_work(){ 
int s,k,t; 
srand(getpid()); 
s = rand_range(SIGRTMIN, SIGRTMAX); 
t = rand_range(10, 20); 
k = t; 
if(sethandler(disarming_handler, s)){ 
    perror("Seting therroryst handeler"); 
    exit(EXIT_FAILURE); 
} 

fprintf(stderr, "[%d] I am therroryst. My disarming signal is [%d]. I will wait [%d] Sec.\n", getpid(), s, t); 
while(k>0) { 
    k=sleep(k); 
    if(disarming_signal == s){ 
     fprintf(stderr, "I got signal [%d]\n.",disarming_signal); 
     return ; 
    } 
} 
fprintf(stderr, "[%d] KABOOM\n",getpid()); 
exit(EXIT_SUCCESS); 
} 
void create_therrorysts(int n){ 
while(n-->0){ 
    switch(fork()) { 
     case 0: 
      therroryst_work(); 
      exit(EXIT_SUCCESS); 
     case -1: 
      perror("Fork():"); 
      exit(EXIT_FAILURE); 
    } 
} 
} 
void sapper_work(){ 
int sig_dis, i; 
struct timespec t, tn = {1,0}; 
fprintf(stderr,"[%d] I am sapper.\n", getpid()); 
for(i=0;i<10;i++){ 
    for(t=tn;nanosleep(&t,&t);); 
    sig_dis = rand_range(SIGRTMIN, SIGRTMAX); 
    if(kill(0, sig_dis)<0){ 
     perror("Disarming_send\n"); 
     exit(EXIT_FAILURE); 
    } 

fprintf(stderr,"I sended signal [%d].\n",sig_dis); 
disarming_signal = sig_dis; 
} 
fprintf(stderr, "end of sending"); 
exit(EXIT_SUCCESS); 
} 

void create_sapper(){ 
switch(fork()) { 
    case 0: 
     sapper_work(); 
     exit(EXIT_SUCCESS); 
    case -1: 
     perror("Fork():"); 
     exit(EXIT_FAILURE); 
} 
} 
int main(int argc, char** argv){ 
int n; 
pid_t pid; 

if(argc != 2){ 
    usage(); 
    return EXIT_FAILURE; 
} 
n = atoi(argv[1]); 

if(n <= 0){ 
    usage(); 
    return EXIT_FAILURE; 
} 

if(sethandler(sigchld_handler, SIGCHLD)) { 
    perror("Seting parent SIGCHLD:"); 
    exit(EXIT_FAILURE); 
} 
create_therrorysts(n); 
create_sapper(); 
sleep(5); 
for(;;) { 
    if(sethandler(SIG_IGN, disarming_signal)){ 
     perror("Seting parent disarming111"); 
     exit(EXIT_FAILURE); 
    } 
} 

for(;;){ 
    pid=wait(NULL); 
    if(pid<0) 
     switch (errno){ 
      case ECHILD: 
       return EXIT_SUCCESS; 
      case EINTR: 
       continue; 
      default: 
       perror("wait:"); 
       exit(EXIT_FAILURE); 
     } 
} 

return EXIT_SUCCESS; 
} 
+0

請勿在信號處理程序中使用printf()。這不是信號安全的。 – wildplasser 2015-03-18 22:49:31

+0

是的你是對的,但即使沒有它,也有我提到的問題。 – 2015-03-19 01:00:24

回答

2

您在create_sapper之後和sethandler(IGN)之前有睡眠(5)。這意味着很可能在您的主進程忽略它之前發送信號。

編輯:從喬納森·萊弗勒添加評論這個答案,因爲它同樣(甚至更多)重要:

還有與設置,即使你把睡眠()的循環後的信號處理的一個問題 - 家長不會看到孩子選擇disarming_signal。

+1

即使您在該循環之後放置了sleep(),父級也無法查看孩子選擇的「disarming_signal」,但設置信號處理程序也存在問題。 – 2015-03-19 00:06:10

+0

是的,很好。這可以說是一個比睡眠更大的問題。 – kaylum 2015-03-19 00:08:11

+0

我想,這很可能是在睡眠後設置爲隨機信號的disarm_signal,因爲如果沒有它,我正在處理掉響鈴信號(初始值爲disarm_signal) – 2015-03-19 01:03:35