2015-03-18 140 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