c - 即使我在父进程中使用 sleep() ,我的子进程也是最后执行的

标签 c process parallel-processing fork sleep

有人可以解释为什么即使我让父进程休眠,父进程总是在子进程中的 while 循环开始之前完全完成。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv) {
    int i = 10000, pid = fork();
    if (pid == 0) {
        while(i > 50) {
            if(i%100==0) {
                sleep(20);
            }
            printf("Child: %d\n", i);
            i--;
        }
    } else {
        while(i < 15000) {
            if(i%50==0) {
                sleep(50);
            }
            printf("Parent: %d\n", i);
            i++;
        }
    }
    exit(EXIT_SUCCESS);
}

输出看起来像这样:

Parent: ..
Parent: ..
Parent: ..

直到 Parent 完成,然后 Child 完成。

会不会是我在单核 CPU 上测试的原因?如果我有一个多核设置,结果会改变吗? sleep(50) 绝对有效——因为脚本完成需要很长时间——为什么 CPU 不切换进程?是否存在诸如在 while 循环期间进程对 CPU 具有“更多”或独占权利的情况?

感谢您的帮助。 :)

最佳答案

Are there situations like for example during a while loop where the process has "more" or exclusive rights to the CPU?

好吧,这还没有定义,但这太疯狂了。

我无法重现您的问题。将 sleep 时间减少到 25 秒(这样我就不必永远等待),child 首先在这里解锁,因为有人会期望。 (Debian 8,Linux 3.16.1-ck1 [BFS 调度程序,非标准] 在 AMD64 上)

我会说你的调度器表现得很奇怪,可能刚刚坏了。但话虽如此,依赖调度程序的任何特定行为绝不是一个好主意。永远假设它是坏的和疯狂的——如果你的代码允许一个特定的执行顺序,那么有一个足够疯狂的调度程序来选择它。(*)

因此,使用同步原语(例如 semaphoresmutexes 具有用于不同进程的共享版本——您也可以只使用管道 在某些情况下)每当您需要依赖某些同步时。

编辑:添加两个用于同步进程的示例。

第一个版本 (ab) 使用 pipes:

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv) {
    int i = 10000;
    int parent_done[2];
    int child_done[2];
    char dummy[1] = { 0 };
    int pid;

    pipe(parent_done);
    pipe(child_done);

    /* stdio buffering would lead to intermingled output */
    setvbuf(stdout, 0, _IONBF, 0);

    pid = fork();

    if (pid == 0) {
        close(parent_done[1]);
        close(child_done[0]);

        while(i > 50) {
            if(i%100==0) {
                if (i < 10000) write(child_done[1], dummy, 1);
                read(parent_done[0], dummy, 1);
            }
            printf("Child: %d\n", i);
            i--;
        }
    } else {
        close(parent_done[0]);
        close(child_done[1]);

        while(i < 15000) {
            if(i%50==0) {
                write(parent_done[1], dummy, 1);
                read(child_done[0], dummy, 1);
            }
            printf("Parent: %d\n", i);
            i++;
        }
    }
    exit(EXIT_SUCCESS);
}

然后同样使用 POSIX 信号量(恕我直言,因为信号量意味着用于同步):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <unistd.h>

struct semaphores
{
    sem_t child_done;
    sem_t parent_done;
};

int main(int argc, char **argv) {
    int i = 10000;
    int pid;

    /* map shared memory for the semaphores */
    struct semaphores *sems = mmap(0, sizeof(*sems), PROT_READ|PROT_WRITE,
            MAP_SHARED|MAP_ANONYMOUS, -1, 0);

    /* initialize both semaphores as "shared" and with an initial count
     * of 0 */
    sem_init(&sems->parent_done, 1, 0);
    sem_init(&sems->child_done, 1, 0);

    /* stdio buffering would lead to intermingled output */
    setvbuf(stdout, 0, _IONBF, 0);

    pid = fork();

    if (pid == 0) {
        while(i > 50) {
            if(i%100==0) {
                if (i < 10000) sem_post(&sems->child_done);
                sem_wait(&sems->parent_done);
            }
            printf("Child: %d\n", i);
            i--;
        }
        sem_post(&sems->child_done);
    } else {
        while(i < 15000) {
            if(i%50==0) {
                sem_post(&sems->parent_done);
                sem_wait(&sems->child_done);
            }
            printf("Parent: %d\n", i);
            i++;
        }
        sem_post(&sems->parent_done);
    }
    exit(EXIT_SUCCESS);
}

Windows 有不同的信号量 API,参见 Semaphore Objects on MSDN

(*) edit2 适合这里:在创建示例时,我注意到 stdio 缓冲在不休眠的情况下妨碍了工作。因此,也许它甚至不是您的调度程序表现不佳,而只是 stdio 的实现,在 何时 刷新缓冲区时具有非常不可预测的行为。当然,这只是胡乱猜测。您必须知道的是:C 中的所有 FILE 句柄都由 C 库的 stdio 部分缓冲。这包括预定义的 stdinstdoutstderr 句柄。结果是您在输出中看到的内容不一定反射(reflect)不同线程或进程创建该输出的顺序。当然,除非您像我的示例片段中那样完全禁用缓冲。

关于c - 即使我在父进程中使用 sleep() ,我的子进程也是最后执行的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33440551/

相关文章:

c++ - 使用pthreads实现线程池

node.js - 通过 java 与终端运行进程之间有区别吗?

java - 并行计算开销

python - Numba 并行代码比顺序代码慢

.net - 并行 visual studio 解决方案构建

c - 如何动态更改c中i/o流中的字符串

c - 如何调试我的 C 数学程序的部分内容?

java - 如何在 Java 中使用控制台运行另一个 Java 进程(在 Linux 中)

process - 如何将 std::process::Command 转换为命令行字符串?

c - 随机数出现在我的类似计算器的程序中