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

时间:2015-10-30 16:22:05

标签: 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循环期间的情况,其中该过程具有&#34;更多&#34;或CPU的专有权?

感谢您的帮助。 :)

1 个答案:

答案 0 :(得分:3)

  

是否存在例如在while循环期间进程对CPU具有“更多”或独占权限的情况?

嗯,这没有定义,但它会疯了。

我无法重现你的问题。将睡眠时间缩短到25秒(因此我不必永远等待), child 首先在此处取消阻止,正如人们所期望的那样。 (AMD64上的Debian 8,Linux 3.16.1-ck1 [BFS调度程序,非标准])

我会说你的调度程序表现得非常奇怪,可能只是被打破了。但话虽如此,依靠调度程序的任何特定行为绝不是一个好主意。总是假设它已经破碎并且疯狂如果 - 如果你的代码允许特定的执行顺序,成为一个疯狂的调度程序来选择它。(*)

因此,使用同步原语(semaphoresmutexes例如有共享版本用于不同的进程 - 您也可以使用pipes某些场景)每当你需要依赖某些同步时。

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

首先使用pipe s:

的版本(ab)
#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句柄。结果是您在输出中看到的内容不一定反映创建输出的不同线程或进程的顺序。当然,除非您完全禁用缓存,就像在我的示例代码段中完成一样。