c - 与信号的简单同步

标签 c linux synchronization signals fork

该程序旨在永久发出交易信号。 SIGUSR1 由父级捕获,SIGUSR2 由子级捕获。当他们捕捉到自己的信号时,他们只玩旗帜。我首先让父进程运行,也就是说,首先父进程发送信号。子进程通过 pause() 等待其进程,直到它动态运行其捕获器。我以为我应用了一个简单的同步,但似乎没有。但是,如果我在 usleep(1000) 中发表评论,则代码可以正常工作。喜欢

initial value, flag = -99
child process, flag = 0
parent process, flag = 1
child process, flag = 0
parent process, flag = 1
child process, flag = 0
.
.
.
child process, flag = 0
parent process, flag = 1
child process, flag = 0
parent process, flag = 1
child process, flag = 0
.
.
.

但是如果不 sleep ,我就无法得到我想要的东西。我想不眠不休地实现我的愿望。错误的输出是,

initial value, flag = -99
parent process, flag = -99
waits forever..................

如何才能按预期运行?然而,这种行为的原因是什么?顺便说一句,我必须仅使用没有信号量、互斥体等的信号来应用同步。所有 posix 信号功能,除了 sleep 、nanosleep 或暂停和忙等待之外,都可以使用,如 sigaction、sigsuspend 等。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

volatile sig_atomic_t flag = -99; // child = 0, parent = 1;



void catcher(int sig) {
    switch (sig) {
    case SIGUSR1 : flag = 1; break;
    case SIGUSR2 : flag = 0; break;
    }
}

int safeBlockParent(int signum) {

    sigset_t maskall, maskmost, maskold;



    sigfillset(&maskall);
    sigfillset(&maskmost);
    sigdelset(&maskmost, signum);
    sigprocmask(SIG_SETMASK, &maskall, &maskold);
    if (flag == 0)
        sigsuspend(&maskmost);
    sigprocmask(SIG_SETMASK, &maskold, NULL);
}

int safeBlockChild(int signum) {
    sigset_t maskall, maskmost, maskold;

    sigfillset(&maskall);
    sigfillset(&maskmost);
    sigdelset(&maskmost, signum);
    sigprocmask(SIG_SETMASK, &maskall, &maskold);
    if (flag == 1)
        sigsuspend(&maskmost);
    sigprocmask(SIG_SETMASK, &maskold, NULL);
}

void  ChildProcess() {


    while(1) {
        safeBlockChild(SIGUSR2);
        fprintf(stderr, "child process, flag = %d\n", flag);
        kill( getppid(), SIGUSR1 );
    }
}

void  ParentProcess(pid_t childPid) {

    flag = 1;

    while(1) {
        //usleep(1000);
        fprintf(stderr, "parent process, flag = %d\n", flag);
        kill( childPid, SIGUSR2 );
        safeBlockParent(SIGUSR1);

    }
}

int main() {

    pid_t  pid;
    struct sigaction sact = { 0 };

    fprintf(stderr, "initial value, flag = %d\n", flag);

    sigemptyset( &sact.sa_mask );
    sact.sa_flags = 0;
    sact.sa_handler = catcher;

    if (sigaction (SIGUSR1, &sact, NULL) < 0) {
        perror("sigaction sigusr1 error");
        exit(1);
    }

    if (sigaction (SIGUSR2, &sact, NULL) < 0) {
        perror("sigaction sigusr2 error");
        exit(2);
    }


    pid = fork();
    if (pid < 0) { perror("fork problem"); exit(3); }

    if (pid == 0) {

        //kill(getppid(), SIGUSR1);
        ChildProcess();
    }

    else {
        ParentProcess(pid);
        //wait(NULL);
    }

    return 0;
}

代码有时会卡住,有时会运行。

最佳答案

您有两个竞争条件:

  1. 父进程可以在子进程有机会为 SIGUSR2 注册信号处理程序之前发送信号。
  2. 一个进程可以在另一个进程处于暂停之外时发送信号。

后者可能会在第一次时发生,此时子进程尚未达到暂停,但父进程已发送SIGUSR2。这会导致您看到的效果。

关于c - 与信号的简单同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49619309/

相关文章:

`read()` 后面可以直接跟 `write()` 吗? `write()` 后面可以直接跟 `read()` 吗?

linux - 没有使用 Net::SFTP::Foreign 的非 root 连接

linux - Linux服务器上崩溃后如何自动重新启动elasticsearch搜索?

c++ - 同一二进制文件中的可执行文件和 DLL/共享库

javascript - cy.fit() 不会立即工作,它需要超时来适应图表。 Cytoscape.js

从 C 中的字符串指针数组创建二维数组

c - 高效的 C 代码,用于查找每个矩阵行中最大数的列索引

c - 返回C中的指针,在字符串中查找值

java - Windows 中 Java 应用程序和 C++ 应用程序之间的同步

python - 使用python实时SQLite和PostgreSQL双向同步