简体   繁体   English

向子进程发送信号,SIGCONT,SIGSTOP

[英]sending signals to child processes , SIGCONT ,SIGSTOP

I have a problem with my code,我的代码有问题,

I want all the children stop when the program start.我希望所有的孩子在节目开始时都停下来。 and after that I want just the child with the index of i to continue executing and others to be stopped .之后,我只希望索引为i的孩子继续执行,而其他人则停止。

I want to execute them in this order p0 ,p1,p2,p3,p4,p0,p1....我想按这个顺序执行它们 p0 ,p1,p2,p3,p4,p0,p1....
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#define N 5

void handler(int i)
{
    if (i == SIGCONT)
    {
        printf("signal cont\n");
    }
}
int main()
{
    int pid[N];
    for (int i = 0; i < N; i++)
    {
        if ((pid[i] = fork()) == 0)
        {
            /* code */
            while (1)
            {
                printf("ici fils %d\n", i);
                usleep(50000);
            }
        }
        else
        {
            kill(pid[i], SIGSTOP);
            // kill(pid[i], SIGSTOP);
            if (i == N - 1)
            {
                kill(pid[i], SIGCONT);
                sleep(2);
                kill(pid[i], SIGSTOP);
                kill(pid[0], SIGCONT);
            }
            else
            {

                kill(pid[i], SIGCONT);
                sleep(2);
                kill(pid[i], SIGSTOP);
                kill(pid[i + 1], SIGCONT);
            }
            // kill(pid[i], SIGKILL);
            waitpid(pid[i], NULL, 0);
        }
    signal(SIGCONT, &handler);
    }
}

There are several issues with your code, among them:您的代码存在几个问题,其中包括:

  1. Any processes to be stopped via SIGSTOP must not have a handler registered for that signal.任何要通过SIGSTOP停止的进程都不得为该信号注册处理程序。 Registering a handler causes the handler's behavior to replace the default behavior of stopping the process.注册处理程序会导致处理程序的行为替换停止进程的默认行为。

  2. It's usually a bad idea to register a handler for SIGCONT .SIGCONT注册处理程序通常是个坏主意。 Doing so will not prevent a SIGCONT from continuing the process, which is a special characteristic of SIGCONT that can be surprising, but also the handler will fire whenever a SIGCONT is delivered, even if the process was not stopped, which is often a different kind of surprise.这样做不会阻止SIGCONT继续进程,这是SIGCONT的一个特殊特性,可能会令人惊讶,而且每当传递SIGCONT时,即使进程没有停止,处理程序也会触发,这通常是不同的类型的惊喜。

  3. You register your signal handlers only in the parent, after the first fork.在第一次分叉之后,您只在父级中注册信号处理程序。 The subsequently forked children will inherit those, but the first one will not.随后分叉的孩子将继承这些,但第一个不会。 Among other things, this will prevent the first child's pause() from being unblocked by the signals the parent sends to it.除此之外,这将防止第一个孩子的pause()被父母发送给它的信号解除阻塞。 You can make each child register any needed handlers for itself, or you can register them in the parent, before the first fork.您可以让每个孩子为自己注册任何需要的处理程序,或者您可以在第一次分叉之前在父项中注册它们。

  4. There is a race between each child's pause() and the parent's first kill() targeting that child.每个孩子的pause()和父母针对该孩子的第一个kill()之间存在竞争。 It is possible for the child to receive the SIGCONT before it calls pause() , in which case it will wait for the next signal.子进程有可能在调用pause()之前收到SIGCONT ,在这种情况下,它将等待下一个信号。 You can prevent that by blocking SIGCONT in the parent before forking, and using sigsuspend() in the child, with an appropriate mask, instead of the initial pause() .您可以通过在分叉之前阻止父级中的SIGCONT并在子级中使用sigsuspend()并使用适当的掩码而不是初始pause()来防止这种情况。 In that case, you probably want to unblock SIGCONT after returning from that initial sigsuspend() .在这种情况下,您可能希望在从初始sigsuspend()返回后解除阻塞SIGCONT

  5. The parent attempts to send signals to processes that it has not forked yet ( kill(pid[i + 1], SIGCONT); ).父进程尝试向尚未分叉的进程发送信号( kill(pid[i + 1], SIGCONT); )。

It's not clear what the full behavior you are trying to achieve is, but you may want to fork all the children first, and only then start sending signals.目前尚不清楚您要实现的完整行为是什么,但您可能希望先分叉所有孩子,然后才开始发送信号。

Update更新

With respect to the update to the question,关于问题的更新,

  1. You apparently want to cycle repeatedly through the child processes, but your code runs through them only once.您显然希望在子进程中反复循环,但您的代码只在它们中运行一次。 This is a good reason to implement what I already suggested above: fork all the children first, then, separately, do all the signalling.这是实现我上面已经建议的一个很好的理由:首先分叉所有的孩子,然后分别做所有的信号。

In the child processes, instead of using pause(2) , use raise(3) to signal the calling process to stop with SIGSTOP .进程中,不要使用pause(2) ,而是使用raise(3)来通知调用进程停止使用SIGSTOP There is no real need to register signal handlers.没有真正需要注册信号处理程序。

In the parent process, after creating a child process, wait for it to stop (or terminate) by using waitpid(2) with the WUNTRACED flag set.进程中,创建进程后,使用设置了WUNTRACED标志的waitpid(2)等待它停止(或终止)。 The WIFSTOPPED(...) macro can be used to specifically determine the status of the child. WIFSTOPPED(...)宏可用于专门确定孩子的状态。 The WCONTINUE flag can be used to wait for a child process to continue, and like before there is the WIFCONTINUED(...) macro. WCONTINUE标志可用于等待进程继续,就像之前有WIFCONTINUED(...)宏一样。

Here is a cursory example, with no meaningful error handling.这是一个粗略的示例,没有任何有意义的错误处理。 Note that concurrent sleeps, while simple, are not technically a consistent way to schedule things.请注意,并发睡眠虽然简单,但在技术上并不是一种一致的安排事情的方式。 The output of this program may differ slightly between executions.该程序的输出在执行之间可能略有不同。

#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

#define CHILDCOUNT 5

sig_atomic_t looping = 1;

void handler(int sig) {
    (void) sig;
    looping = 0;
}

pid_t create_child(void) {
    pid_t pid = fork();

    if (!pid) {
        /* child */
        raise(SIGSTOP);
        pid_t self = getpid();
        printf("SIGCONT in %d\n", self);

        while (1) {
            printf("RUNNING in %d\n", self);
            sleep(1);
        }

        /* bug net */
        exit(EXIT_SUCCESS);
    }

    return pid;
}

void killwait(pid_t pid, int sig) {
    kill(pid, sig);

    int status;
    waitpid(pid, &status, WUNTRACED | WCONTINUED);

    if (WIFSTOPPED(status))
        printf("P: C(%d) STOPPED!\n", pid);
    if (WIFCONTINUED(status))
        printf("P: C(%d) CONTINUED!\n", pid);
    if (WIFSIGNALED(status) && SIGKILL == WTERMSIG(status))
        printf("P: C(%d) SUCCESSFULLY KILLED!\n", pid);
}

int main(void) {
    pid_t pids[CHILDCOUNT];

    /* tentative: catch this in all processes so the parent may reap manually */
    signal(SIGINT, handler);

    for (size_t i = 0; i < CHILDCOUNT; i++) {
        pid_t current = pids[i] = create_child();

        printf("Parent now has child (%d) [#%zu].\n", current, i);
        killwait(current, 0);
    }

    for (size_t i = 0; looping; i = (i + 1) % CHILDCOUNT)  {
        pid_t current = pids[i];

        printf("P: C(%d) STARTING [#%zu].\n", current, i);

        killwait(current, SIGCONT);
        sleep(2);
        killwait(current, SIGSTOP);
    }

    for (size_t i = 0; i < CHILDCOUNT; i++)
        killwait(pids[i], SIGKILL);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM