0

したがって、私のタスクは、親とその 2 人の子供をこの方法で同期させることです。1 つの子供が SIGUSR2 シグナルを親に送信し、待機中の親メッセージをブロックします。同期はグローバル フラグによって実装されるため、親は flag_ch のいずれかが 1 になるのを待機し (子が SIGUSR2 を送信したときに発生します)、シグナル SIGUSR1 をこの子に送信し、子は再開します (グローバル flag_p が 1 になるため)。

問題は、親が 1 つの子からのみシグナルを受信し、次に 2 番目の子シグナルを待機するのをブロックすることですが、それらは表示されません。何か案が?..

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/signalfd.h>
#define LPC 10
pid_t ch[2];

sig_atomic_t flag_ch[2] = {0, 0};
sig_atomic_t flag_p = 0;

int get_ind(pid_t ch_pid) {
    int i;
    for (i = 0; i < 2; ++i) {
        if (ch_pid == ch[i])
            return i;
    }
    return -1;
}

void usr_handler(int signo, siginfo_t* si, void* unused) {
    int ch_index;
    switch(signo) {
        case SIGUSR2:
            ch_index = get_ind(si->si_pid);
            if (ch_index >= 0)
                flag_ch[ch_index] = 1;
            else
                fprintf(stderr, "signal handled not from child pid %d\n", si->si_pid);
            break;
        case SIGUSR1:
            flag_p = 1;
            break;
    }
}

void set_usr_handler(void) {
    struct sigaction sa;
    sa.sa_sigaction = usr_handler;
    sa.sa_flags = SA_SIGINFO;
    sa.sa_restorer = NULL;

    sigemptyset(&sa.sa_mask);

    if (0 != sigaction(SIGUSR1, &sa, NULL))
        abort_prg("signal [SIGUSR1] error");

    if (0 != sigaction(SIGUSR2, &sa, NULL))
        abort_prg("signal [SIGUSR2] error");
}


void child_proc(void) {
    int i;
    for (i = 0; i < LPC; ++i) {
        if (0 != kill(getppid(), SIGUSR2))
            exit(1);
        while (0 == flag_p) { };
            flag_p = 0;
    }
}

int wait_child(void) {
    while (0 == flag_ch[0] && 0 == flag_ch[1]) { };
    if (1 == flag_ch[0]) {
        flag_ch[0] = 0;
        return ch[0];
    }
    flag_ch[1] = 0;
    return ch[1];
}

void parent_proc(void) {
    int i;
    pid_t ch_pid;
    for (i = 0; i < LPC * 2; ++i) {
        ch_pid = wait_child();
        printf("Parent: Received from pid [%d]\n", ch_pid);
        if (0 != kill(ch_pid, SIGUSR1))
            exit(1);
    }
}

int main(int argc, char* argv[]) {
    set_usr_handler();
    int i;
    for (i = 0; i < 2; ++i) {
        pid_t child = fork();
        if (0 > child)
            exit(1);
        if (0 == child) {
            child_proc();
            return 0;
        }
        ch[i] = child;
    }   
    parent_proc();
    return 0;
}
4

1 に答える 1

0

私の推測ではvolatile、いくつかのグローバル変数宣言で欠落していると思われます。たとえば、flag_pないというvolatileことは、ループが

while (flag_p == 0) { }

永久に実行できます: GCC はおそらくそれをコンパイルして、グローバル変数を一度だけレジスタにロードし、その後、このレジスタが非ゼロになるまでループします (決して発生しません)。

保守的な概算volatileとして、シグナル ハンドラで読み書きされるすべての変更可能な変数を作成する必要があります。

編集:私が考えることができる問題の別の原因は、シグナルが累積的ではないことです:親プロセスに保留中のSIGUSR2がないか、1つあります。両方の子が同時に親プロセスに送信した場合、私の知る限り、1 つだけが配信される可能性があります。

編集:「より良い」解決策(より柔軟で移植性が高い)は、次のようになると思います:信号をまったく使用せず、パイプを使用します。親と各子の間に 1 つのパイプを作成し、完了時に子はパイプを介して文字 'X' を送信します。親は select(); で待機します。または、両方の子の準備が整うまで待ちたい場合は、一方のパイプから 'X' 文字を読み取り、次にもう一方のパイプから読み取り、両方のケースでブロックします (順序は関係ありません)。

于 2013-04-18T13:08:30.640 に答える