2016-04-10 16 views
0

私はlinuxでシグナルを使う方法を学んでいます。 4つの子プロセスと1つの親プロセスがあります。私の出力は、これらのステージに行くことになっている:シグナルを使った親プロセスと複数の子プロセスのプロセス同期

親は、子供からの信号を受信する1

親は子からの信号を受信する2

親が3

親が子供4からの信号を受信した子からの信号を受信し、

initは

フェーズ1は

を開始します終了しました

子1が親からの信号を受信

2子供が親からの信号を受信

子3は親からの信号を受信

子4は

親が子供1

からの信号を受信した親からの信号を受信します

親は子供2からの信号を受信する

親は子からの信号を受信する3

親は子からの信号を受信する4

フェーズ1が終了

フェーズ2

子1が親からの信号を受信し始める子2からの信号を受信

子供3は親からの信号を受信

子供4が親からの信号を受信

フェーズ1が終了する前に、私は現在苦労しています。ここに私のコードは次のとおりです。

#include <unistd.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
#define MAXCP 3 
int ccount=0; 
void p_action(int sig){ 
    if (sig == SIGUSR2){ 
     printf("\ncontroller(%d): Received signal SIGUSR2 from child process\n", 
      (int)getpid()); 
    } 
    --ccount; 
} 

void c_action(int sig){ 
    if (sig == SIGUSR1){ 
     printf("\ncompute(%d): Received signal SIGUSR1 from parent process %d\n", 
      (int)getpid(), (int)getppid()); 
    } 
    exit(0); 
} 

int main(){ 

pid_t pid[MAXCP], parent_pid; 
//int nprocs = 0; 
ccount = MAXCP; 

static struct sigaction pact, cact[MAXCP]; 

pact.sa_handler = p_action; 
sigaction(SIGUSR2, &pact, NULL); 


int count; 
for (count = 0; count < MAXCP; count++){ 
    switch(pid[count] = fork()){ 
     case -1: 
      perror("Fork error"); 
      exit(1); 
     case 0: 
      //sleep(1); 
      cact[count].sa_handler = c_action; 
      sigaction(SIGUSR1, &cact[count], NULL); 
      printf("Sending SIGUSR2 to parent"); 
      kill(getppid(), SIGUSR2); 
      pause(); 
      break; 
     default: 
      pause(); 
      //printf("Parent is sleeping"); 

      while (ccount != MAXCP){ 
       sleep(60); 
      } 
      for (ccount = 0; ccount < MAXCP; ccount++) 
       kill(pid[count], SIGUSR1); 
      break; 

    } 
} 


return 0; 
} 

私の出力は、次のとおりです。お時間を

// When I use the above code 
controller(3132): Received signal SIGUSR2 from child process 
// When I comment out the pause in the child section 
controller(3140): Received signal SIGUSR2 from child process 
Sending SIGUSR2 to parent 
controller(3141): Received signal SIGUSR2 from child process 
Sending SIGUSR2 to parentSending SIGUSR2 to parentSending SIGUSR2 to  parentSending SIGUSR2 to parentSending SIGUSR2 to parent 
controller(3142): Received signal SIGUSR2 from child process 
^C 

感謝。

+0

'--ccount;'は未定義です。シグナルハンドラでのみ 'volatile sig_atomic_t'オブジェクトを使用できます。最悪の場合、シグナルハンドラは 'ccount!= MAXCP'の途中でバイトを変更したり、それを他の方法で使用したり、同様に悪いものを修正したりします。 –

+0

私は揮発性のsig_atomic_tを入れ、私はまだ同じ結果に行きます。 – corax

+0

解決策として、それが未定義の振る舞いであったことを指摘しただけではなく、現在または後の全体的な奇妙さに貢献するかもしれません。 –

答えて

1

信号を使用したいと思うものは、設計したものと100%一致していません。最も重要な問題は、信号がハードウェア割り込みコントローラとして機能することです。同じ値の複数の信号が「同時に」発生した場合、それらは受信機のただ1つの信号にマージされているように見えます。以下の例では、各子で異なる値のsleepを使用してこの問題を回避しています。

カーネルがプロセスのスケジュールを変更するときは、前回のプロセスがアクティブだったときから各シグナルが受信されたかどうかを確認し、必要に応じてプロセスに転送します。それは何回起きたのか分かりません。

#include <unistd.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <stdio.h> 
#include <stdlib.h> 
#define MAXCP 3 
volatile int ccount=0; 
void p_action(int sig, siginfo_t *info, void *ptr){ 
    if (sig == SIGUSR2){ 
     printf("\ncontroller(%d): Received signal SIGUSR2 from child %d process\n", 
      (int)getpid(), (int)info->si_pid); 
    } 
    --ccount; 
} 

void c_action(int sig){ 
    if (sig == SIGUSR1){ 
     printf("\ncompute(%d): Received signal SIGUSR1 from parent process %d\n", 
      (int)getpid(), (int)getppid()); 
    } 
} 

int main(){ 
    int count; 
    pid_t pid[MAXCP]; 
    ccount = MAXCP; 

    struct sigaction pact; 

    pact.sa_flags = SA_SIGINFO | SA_RESTART; /* if signal comes on top of each other, we need this */ 
    pact.sa_sigaction = p_action; 
    sigaction(SIGUSR2, &pact, NULL); 

    /* spawdn children */ 
    for (count = 0; count < MAXCP; count++){ 
     switch(pid[count] = fork()){ 
      case -1: 
       perror("Fork error"); 
       exit(1); 
      case 0: 
       { 
        struct sigaction cact; 
        cact.sa_flags = 0; 
        cact.sa_handler = c_action; 
        sigaction(SIGUSR1, &cact, NULL); 
        pause(); 
        sleep(1); 
        printf("Sending SIGUSR2 to parent (%d)\n", getppid()); 
        sleep(count+1); 
        kill(getppid(), SIGUSR2); 
        exit(0); 
        break; 
       } 
      default: 
       break; 
     } 
    } 

    sleep (1); /* let children have time to configure sigaction() */ 

    /* notify all children */ 
    for (count = 0; count < MAXCP; count++){ 
     printf ("Sending SIGUSR1 to child %d\n", (int)pid[count]); 
     kill(pid[count], SIGUSR1); 
    } 

    /* wait for children to notify back */ 
    while (ccount) 
    { 
     usleep(10000); /* else CPU throttles */ 
    } 

    for (count = 0; count < MAXCP; count++){ 
     int status; 
     waitpid (pid[count], &status, 0); 
     printf ("Child process %d reaped. status=%d\n", pid[count], status); 
     kill(pid[count], SIGUSR1); 
    } 

    return 0; 
} 

イメージカーネルには、スリープ中に受信した信号に関するプロセスごとのレコードがあります。

struct Process 
{ 
    bool hasReceivedSIGINT; 
    bool hasReceivedSIGUSR1; 
    bool hasReceivedSIGUSR2; 
    bool hasReceivedSIGUSR3; 
}; 

シグナルは、他のプロセスを「ナッジする」ために使用されます。良い例は、プロセスリロード構成ファイルを作ることです。 IPC通信の場合、pipe()はより良いアプローチです。

+0

Stian:ありがとう。あなたはこの問題を考える上で私を助けてくれました。 – corax

関連する問題