当前位置:  开发笔记 > 运维 > 正文

两个进程之间的顺序信号

如何解决《两个进程之间的顺序信号》经验,为你挑选了1个好方法。

我有一个父进程和两个孩子.父进程只创建两个孩子,一个读者和一个计数器,并等待它的死亡.孩子们做了以下事情.

第一个孩子(读者):

    打开文件,

    读一条线,

    向第二个孩子发送信号(SIGUSR1),

    等待第二个孩子的信号,

    如果我们可以读另一行,请转到2,否则杀死第二个孩子.

第二个孩子(柜台):

    等待读者的信号(SIGUSR1),

    计算线长,

    向读者发送信号并转到1.

我等待来自另一个进程的信号时遇到麻烦.在调用pause()函数之前可以接收信号,即可以永久阻止进程.我还试图用sigprocmask(),sigsuspend()sigwaitinfo(),但它不能正常工作.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

enum { MAX_LEN = 16 };

void handler(int signo)
{
    // do nothing
}

int main(int argc, const char * argv[])
{
    sigset_t ss;
    sigemptyset(&ss);
    sigaddset(&ss, SIGUSR1);

    // handle SIGUSR1
    signal(SIGUSR1, handler);

    // shared memory for file line
    char *data = mmap(NULL, MAX_LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

    pid_t *pid_counter = mmap(NULL, sizeof(*pid_counter), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);

    pid_t pid_reader;
    if (!(pid_reader = fork())) {
        sigprocmask(SIG_BLOCK, &ss, NULL);
        printf("READER: waiting signal from COUNTER\n"); fflush(stdout);
        sigwaitinfo(&ss, NULL);
        sigprocmask(SIG_UNBLOCK, &ss, NULL);
        printf("READER: got signal\n"); fflush(stdout);

        printf("READER: opening file\n"); fflush(stdout);
        FILE *f = fopen(argv[1], "r");
        while (fgets(data, MAX_LEN, f) > 0) {
            printf("READER: reading line and waiting signal from COUNTER\n"); fflush(stdout);

            sigprocmask(SIG_BLOCK, &ss, NULL);
            kill(*pid_counter, SIGUSR1);
            sigwaitinfo(&ss, NULL);
            sigprocmask(SIG_UNBLOCK, &ss, NULL);

            printf("READER: got signal\n"); fflush(stdout);
        }
        printf("READER: closing file and killing COUNTER\n"); fflush(stdout);
        fclose(f);
        kill(*pid_counter, SIGTERM);
        _exit(0);
    }

    if (!(*pid_counter = fork())) {
        sleep(1);
        printf("COUNTER: send signal to READER that COUNTER is ready\n"); fflush(stdout);
        while (1) {
            sigprocmask(SIG_BLOCK, &ss, NULL);
            kill(pid_reader, SIGUSR1);
            printf("COUNTER: waiting signal from READER\n"); fflush(stdout);
            sigwaitinfo(&ss, NULL);
            sigprocmask(SIG_UNBLOCK, &ss, NULL);
            printf("COUNTER: got signal\n"); fflush(stdout);

            printf("%d\n", strlen(data));
            fflush(stdout);
        }
    }

    wait(NULL);
    wait(NULL);

    return 0;
}

对于此代码,我可以得到以下序列:

$ gcc -o prog prog.c && ./prog input.dat
READER: waiting signal from COUNTER
COUNTER: send signal to READER that COUNTER is ready
COUNTER: waiting signal from READER
READER: got signal
READER: opening file
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: reading line and waiting signal from COUNTER
READER: got signal
READER: closing file and killing COUNTER

为什么计数器不写"有信号"?我如何同步发送和接收信号?(我知道其他IPC方法,但我需要通过信号进行同步.)



1> Crowman..:

这里有一些明显的问题.

实际导致您的问题的是:

if (!(*pid_counter = fork())) {

记住(1)pid_counter指向共享内存; (2)每次调用时fork()返回两次.当它在子节点中返回时,它将设置*pid_counter0,但当它在父节点中返回时,它将设置*pid_counter为子节点的PID.你无法预测哪一个会先发生.在您的情况下实际发生的是它最终设置为0,因此kill读取器进程中的所有调用都向您的进程组中的每个进程发送信号,因此读取器和计数器都同时获取它们.这导致同步失败,因为两个进程同时返回sigwaitinfo().在阅读器中,您应该只发送SIGUSR1到计数器进程.

您需要做的是将其更改为:

pid_t temp_pid
if ( !(temp_pid = fork()) ) {
    *pid_counter = getpid();

其他要点:

    sigprocmask()保留在fork()调用之间,所以你应该在之前设置它一次fork().你永远不需要在你的情况下取消阻止,不应该.

    SIGUSR1如果你正在调用sigwaitinfo()它,就没有必要(并且可以说最好不要)建立一个处理程序.

    strlen()返回类型size_t,因此您的printf()格式说明符应该是%zu,而不是%d.

    你所有的电话fflush(stdout),虽然无害,但在这里是多余的.

    你几乎没有检查系统调用的任何回报.这不仅仅适用于生产代码 - 如果您的程序无法运行,首先要做的就是验证您是否检查了所有系统调用是否成功,因为它可能无法正常工作的原因是因为其中一个调用是失败,也许是因为你传递了不好的信息.在测试程序时检查是否成功更为重要,同样重要.

无论如何,这是你的程序的工作版本:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

enum { MAX_LEN = 16 };

int main(int argc, const char * argv[])
{
    if ( argc != 2 ) {
        fprintf(stderr, "Enter one argument, and one argument only.\n");
        return EXIT_FAILURE;
    }

    // shared memory for file line
    char *data = mmap(NULL, MAX_LEN, PROT_READ | PROT_WRITE, MAP_SHARED |
                      MAP_ANON, -1, 0);
    if ( data == MAP_FAILED ) {
        perror("mmap() failed for data");
        exit(EXIT_FAILURE);
    }

    pid_t *pid_counter = mmap(NULL, sizeof *pid_counter, PROT_READ |
                              PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
    if ( pid_counter == MAP_FAILED ) {
        perror("mmap() failed for pid_counter");
        exit(EXIT_FAILURE);
    }

    pid_t pid_reader, temp_pid;

    sigset_t ss;
    sigemptyset(&ss);
    sigaddset(&ss, SIGUSR1);
    if ( sigprocmask(SIG_BLOCK, &ss, NULL) == -1 ) {
        perror("sigprocmask() failed");
        exit(EXIT_FAILURE);
    }

    if ( (pid_reader = fork()) == -1 ) {
        perror("fork() failed for reader");
        exit(EXIT_FAILURE);
    }
    else if ( !pid_reader ) {
        printf("READER: waiting signal from COUNTER\n");

        if ( sigwaitinfo(&ss, NULL) == -1 ) {
            perror("sigwaitinfo() failed in reader");
            _exit(EXIT_FAILURE);
        }

        printf("READER: got signal\n");

        printf("READER: opening file\n");

        FILE *f = fopen(argv[1], "r");
        if ( !f ) {
            fprintf(stderr, "Couldn't open input file\n");
            _exit(EXIT_FAILURE);
        }

        while ( fgets(data, MAX_LEN, f) ) {
            printf("READER: reading line and waiting signal from COUNTER\n");

            if ( kill(*pid_counter, SIGUSR1) == -1 ) {
                perror("kill() for SIGUSR1 failed in reader");
                _exit(EXIT_FAILURE);
            }

            if ( sigwaitinfo(&ss, NULL) == -1 ) {
                perror("sigwaitinfo() failed in reader");
                _exit(EXIT_FAILURE);
            }

            printf("READER: got signal\n");
        }
        printf("READER: closing file and killing COUNTER\n");
        fclose(f);
        if ( kill(*pid_counter, SIGTERM) == -1 ) {
            perror("kill() for SIGTERM failed in reader");
            _exit(EXIT_FAILURE);
        }

        _exit(EXIT_SUCCESS);
    }

    if ( (temp_pid = fork()) == -1 ) {
        perror("fork() failed for counter");
        exit(EXIT_FAILURE);
    }
    else if ( temp_pid == 0 ) {
        *pid_counter = getpid();

        sleep(1);
        printf("COUNTER: send signal to READER that COUNTER is ready\n");

        while (1) {
            if ( kill(pid_reader, SIGUSR1) == -1 ) {
                perror("kill() failed for SIGUSR1 in counter");
                _exit(EXIT_FAILURE);
            }

            printf("COUNTER: waiting signal from READER\n");

            if ( sigwaitinfo(&ss, NULL) == -1 ) {
                perror("sigwaitinfo() failed in counter");
                _exit(EXIT_FAILURE);
            }

            printf("COUNTER: got signal\n");

            printf("%zu\n", strlen(data));
        }

        _exit(EXIT_SUCCESS);
    }

    if ( wait(NULL) == -1 ) {
        perror("first wait() failed");
        exit(EXIT_FAILURE);
    }

    if ( wait(NULL) == -1 ) {
        perror("second wait() failed");
        exit(EXIT_FAILURE);
    }

    return 0;
}

使用以下输出显示的文件:

paul@thoth:~/src$ cat file.txt
line one
line two
line three

paul@thoth:~/src$ ./sig file.txt
READER: waiting signal from COUNTER
COUNTER: send signal to READER that COUNTER is ready
COUNTER: waiting signal from READER
READER: got signal
READER: opening file
READER: reading line and waiting signal from COUNTER
COUNTER: got signal
9
COUNTER: waiting signal from READER
READER: got signal
READER: reading line and waiting signal from COUNTER
COUNTER: got signal
9
COUNTER: waiting signal from READER
READER: got signal
READER: reading line and waiting signal from COUNTER
COUNTER: got signal
11
COUNTER: waiting signal from READER
READER: got signal
READER: reading line and waiting signal from COUNTER
COUNTER: got signal
1
COUNTER: waiting signal from READER
READER: got signal
READER: closing file and killing COUNTER
paul@thoth:~/src$ 

推荐阅读
wurtjq
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有