unix 仅用信号同步N进程

m1m5dgzv  于 2022-11-04  发布在  Unix
关注(0)|答案(1)|浏览(203)

我正在做一个操作系统课程的练习。为了学习使用信号(我的一个弱点),我想尝试只用信号同步N个进程。但是我做不到。
代码为:


# include "Header.h"

# include <signal.h>

// first sigHandler
void sigHandler(int signum)
{    
    printf("Received signal\n");
}

// second sigHandler
void sigHandler2(int signum)
{
    printf("Received other signal\n");
}

int main(int argc, char *argv[])
{
    // Number of process
    int N = 2;

    // Assign sigHandlers
    signal(SIGUSR1, sigHandler);
    signal(SIGUSR2, sigHandler2);

    // array for pids to activate in order;
    pid_t pid[N];

    int i;

    for (i = 0; i < N; i++)
    {
        // creation child
        pid[i] = fork();

        if (pid == 0)
        {
            // if is the last child, resume the father
            if (i == N - 1)
            {
                kill(getppid(), SIGUSR2);
            }

            // expect SIGUSR1
            pause();
            printf("%i completed\n", getpid());
            exit(0);
        }
    }

    // expext that all child started
    pause();

    // active the last child
    i--;
    kill(pid[i], SIGUSR1);
    signal(SIGUSR1, sigHandler);

    // active other child
    while (wait(NULL) != -1)
    {
        i--;
        kill(pid[i], SIGUSR1);
        signal(SIGUSR1, sigHandler);
    }
    printf("All fine\n");
    exit(0);
}

我尝试用sleep(10)替换pause()系统,但结果是终端上出现四条“All fine”消息。
我猜想这个问题源于信号的异步特性,但我不知道如何解决它。

whitzsjs

whitzsjs1#

问题的主要部分是测试if (pid == 0)-数组地址不为空。您的意思是if (pid[i] == 0)
通过这些更改以及使代码在我的默认编译选项(非常繁琐)下编译所需的最小更改,我从程序sig79中得到了以下输出:

$ sig79
Received other signal
Received signal
15312 completed
Received signal
15311 completed
All fine
$

在调试问题时,我使用了这段代码,它有大量的打印内容(部分原因是我被有缺陷的测试弄糊涂了)。我使用等待循环是因为在某些情况下,您的父进程可能会有它没有创建的子进程--这些情况很模糊,但这段代码说明了这些情况。注意,子进程退出时的状态与子进程编号相对应;您可以在等待循环中报告的退出状态中看到这些数字。


# include <assert.h>

# include <signal.h>

# include <stdio.h>

# include <stdlib.h>

# include <sys/wait.h>

# include <unistd.h>

static void write_msg(size_t len, char *msg)
{
    int pid = getpid();
    for (int i = 5; i > 0; i--)
    {
        msg[i-1] = pid % 10 + '0';
        pid /= 10;
    }
    write(STDOUT_FILENO, msg, len);
}

// first sigHandler
static void sigHandler1(int signum)
{    
    assert(signum == SIGUSR1);
    static char msg[] = "XXXXX: Received signal SIGUSR1\n";
    write_msg(sizeof(msg) - 1, msg);
}

// second sigHandler
static void sigHandler2(int signum)
{
    assert(signum == SIGUSR2);
    static char msg[] = "XXXXX: Received signal SIGUSR2\n";
    write_msg(sizeof(msg) - 1, msg);
}

int main(void)
{
    // Number of process
    int N = 2;

    // Assign sigHandlers
    signal(SIGUSR1, sigHandler1);
    signal(SIGUSR2, sigHandler2);

    printf("%d: parent at work\n", getpid());

    // array for pids to activate in order;
    pid_t pid[N];

    for (int i = 0; i < N; i++)
    {
        // creation child
        pid[i] = fork();

        if (pid[i] == 0)
        {
            printf("%d: child %d at play\n", getpid(), i+1);
            // if is the last child, resume the father
            if (i == N - 1)
            {
                kill(getppid(), SIGUSR2);
                printf("%d: signal SIGUSR2 sent to PID %d\n", getpid(), getppid());
            }

            // expect SIGUSR1
            pause();
            printf("%d: child %d completed\n", getpid(), i+1);
            exit(i+1);
        }
        printf("%d: child %d has PID %d\n", getpid(), i+1, pid[i]);
        fflush(stdout);
    }

    // expect that all children started
    pause();

    for (int i = N; i > 0; i--)
    {
        kill(pid[i - 1], SIGUSR1);
        printf("%d: signal SIGUSR1 sent to child %d PID %d\n", getpid(), i, pid[i - 1]);
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
        {
            if (corpse == pid[i - 1])
            {
                printf("%d: child %d PID %d exited with status 0x%.4X\n",
                       getpid(), i, corpse, status);
                break;
            }
            else
                printf("%d: unexpected child PID %d exited with status 0x%.4X\n",
                       getpid(), corpse, status);
        }
    }

    printf("%d: All fine\n", getpid());
    return(0);
}

有一次,当我运行程序(sig59)时,我得到了输出:

$ sig59
15177: parent at work
15177: child 1 has PID 15178
15178: child 1 at play
15177: child 2 has PID 15179
15179: child 2 at play
15179: signal SIGUSR2 sent to PID 15177
15177: Received signal SIGUSR2
15177: signal SIGUSR1 sent to child 2 PID 15179
15179: Received signal SIGUSR1
15179: child 2 completed
15177: child 2 PID 15179 exited with status 0x0200
15177: signal SIGUSR1 sent to child 1 PID 15178
15178: Received signal SIGUSR1
15178: child 1 completed
15177: child 1 PID 15178 exited with status 0x0100
15177: All fine
$

并且,为了证明模糊情况可能发生:

$ forker -s 0 -c 'exit 37' -- ./sig59
forker: Setting number of child processes to 3
15138: forker at work
15138: launched 15139
15138: launched 15140
15138: launched 15141
15138: executing ./sig59
15138: parent at work
15138: child 1 has PID 15142
15138: child 2 has PID 15143
15142: child 1 at play
15143: child 2 at play
15143: signal SIGUSR2 sent to PID 15138
15138: Received signal SIGUSR2
15138: signal SIGUSR1 sent to child 2 PID 15143
15143: Received signal SIGUSR1
15143: child 2 completed
15138: child 2 PID 15143 exited with status 0x0200
15138: signal SIGUSR1 sent to child 1 PID 15142
15138: unexpected child PID 15139 exited with status 0x2500
15142: Received signal SIGUSR1
15142: child 1 completed
15138: unexpected child PID 15140 exited with status 0x2500
15138: unexpected child PID 15141 exited with status 0x2500
15138: child 1 PID 15142 exited with status 0x0100
15138: All fine
$

forker程序运行三个进程,每个进程依次运行exit 37(十六进制0x 25),然后执行sig59进程(它不知道它以前的子进程是forker进程)。

相关问题