使用C语言中的信号量进行并行处理和同步

时间:2016-01-02 20:16:31

标签: c unix parallel-processing fork posix

问题:

  1. 我的进程是否并行运行? 我想要并行运行六个进程。
  2. 如何在无限循环中使用信号量同步这些进程(父进程有五个子进程)?因此输出将是:1 2 3 4 5重置1 2 3 4 5重置等...
  3. 任何简单易懂的信号量文档?
  4. 代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    parentWithFiveChildren()
    {   
        printf("1 "); //Parent
        fflush(stdout);
    
        int i, status;
    
        for (i = 2; i < 7; i++)
        {   
            sleep(1); 
            if (fork() == 0) //Child Processes
            {               
                if (i == 6) 
                {
                    printf("reset "); 
                    fflush(stdout);
                    exit(0);
                }
                printf("%d ", i); 
                fflush(stdout);
                sleep(7); 
                exit(i); //Exiting child processes
            }
        }
    
        while ((wait(&status)) > 0)
        printf("\a");
        return 0;
    }
    
    int main(void)
    {
        parentWithFiveChildren();
    }
    

    输出:

    1 2 3 4 5 reset
    

3 个答案:

答案 0 :(得分:4)

1。并行

不,这些流程并非并行运行(或者,至少它们只是短暂并行运行,一次只运行两个流程),只是因为:

  1. sleep(1)为父进程提供了很长时间(至少一秒钟)无所事事。
  2. 孩子在那一秒钟内完成并退出。
  3. 您孩子的打印代码很奇怪; i == 6和其他操作之间实际上没有区别。在main()中,return 0;exit(0);几乎相同 - 可能存在差异,但它们模糊不清,与您的代码没有密切关系。

    你应该#include <sys/wait.h>并且你应该收集死去的孩子的PID(和状态);它会让你更清楚。

    你也可以让孩子们报告一段时间的睡眠(比如每次7秒)。这会让你所有的子进程并行运行(实际上是睡觉),然后父进程等待子进程退出:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    int main(void)
    {
        printf("[PARENT] with pid %d\n", getpid()); 
        fflush(stdout);
    
        for (int i = 2; i < 7; i++)  // Odd loop conditions, but not wrong
        {   
            sleep(1); 
            if (fork() == 0)
            {   
                printf("[CHILD] with pid %d from parent with pid %d\n", getpid(), getppid()); 
                fflush(stdout);
                sleep(7);
                printf("[CHILD] with pid %d exiting with status %d\n", getpid(), i); 
                exit(i);
            }
        }
    
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
        return 0;
    }
    

    示例输出:

    $ ./test-forking
    [PARENT] with pid 13904
    [CHILD] with pid 13905 from parent with pid 13904
    [CHILD] with pid 13906 from parent with pid 13904
    [CHILD] with pid 13907 from parent with pid 13904
    [CHILD] with pid 13908 from parent with pid 13904
    [CHILD] with pid 13909 from parent with pid 13904
    [CHILD] with pid 13905 exiting with status 2
    13904: child 13905 exited with status 0x0200
    [CHILD] with pid 13906 exiting with status 3
    13904: child 13906 exited with status 0x0300
    [CHILD] with pid 13907 exiting with status 4
    13904: child 13907 exited with status 0x0400
    [CHILD] with pid 13908 exiting with status 5
    13904: child 13908 exited with status 0x0500
    [CHILD] with pid 13909 exiting with status 6
    13904: child 13909 exited with status 0x0600
    $
    

    对代码的升级也会打印每行输出的时间。

    2。杀死

    任何进程(在父级创建的集合中)都可以使用kill()系统调用终止它所知道的任何其他进程(在集合中)。目前尚不清楚您是想让第一个孩子还是最后一个孩子杀死父母或其他东西。如果第一个孩子杀死了父母,那么第一个孩子将是唯一的孩子(因为延迟)。还不清楚为什么要在进程之间发送信号。

    3。循环

    是的,你可以做点什么 - 问题是,你真正追求的是什么。简单地多次打印parentchild不需要多个进程。如果你想让父母说“我在这里”,并且每个孩子定期说“我在这里”,你需要让孩子们循环和睡觉,并且在所有孩子都被创建之后父母循环和睡觉。不难做到。

答案 1 :(得分:2)

问题3)。 ...我可以将main函数置于无限循环中......

当然可以

int  main(void)
{
    int c=0;
    while((c != 'q') && (c != EOF))//loops until c == q (and c!=EOF)
    {
        c = getchar();//waits until stdin sees a "q", (i.e. from keyboard)

        //An EOF (-1) or `q` will exit the loop
        //any other input will allow execution flow to continue, 1 loop at a time.  
        //Add additional forking code here.           
        //for each loop, spawn a new thread.
        //All secondary threads spawned will run parallel to other threads.
    }
    //exiting here will kill all threads (secondary and primary.)
    return 0;
}

答案 2 :(得分:1)

1)是的,您的父进程和子进程在fork后并行运行, 您可以通过无限循环子进程看到这一点,并在父进程和其他进程执行相同操作时打印它的名称。

2)是的,方法如下:

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

int main()
{
    pid_t pid;
    int i = 0;

    if ((pid = fork()) == 0)
    {
        if ((pid = getppid()) == -1)
        {
            fprintf(stderr, "child error: getppid()\n");
            exit(1);
        }
        if (kill(pid, 9) == -1)
        {
            fprintf(stderr, "child error: kill()\n");
            exit(1);
        }

        while (true)
        {
            printf ("child %d\n", ++i);
        }
    }
    else if (pid == -1)
    {
        fprintf(stderr, "error: fork()\n");
        return 1;
    }

    while (true)
    {
        printf("parent %d\n", ++i);
    }

    return 0;
}

3)如果需要特定模式,则需要进程间通信和同步。建议this