📜  使用fork()在4个过程中进行多次计算(1)

📅  最后修改于: 2023-12-03 14:49:48.212000             🧑  作者: Mango

多进程编程:使用fork()在4个过程中进行多次计算

介绍

在多进程编程中,fork()函数提供了一种创建新进程的方法。通过fork(),可以将一个父进程拆分成多个子进程,在各个进程中并行运行不同的任务。这种方法通常被用于处理大规模的计算和应用,并且可显著提高程序的执行效率。

本文将介绍如何使用fork()函数,在四个不同的进程中进行多次计算。这四个进程将并行执行,并在结束时返回计算结果给主进程。

代码实现
1. 主进程

首先,我们需要在主进程中设置必要的变量和参数。在这个例子中,我们将计算使用随机数生成的1000个数字的总和。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define NUM_CHILDREN 4
#define NUM_VALUES 1000
int values[NUM_VALUES];

int main() {
    // 生成1000个随机数
    for (int i = 0; i < NUM_VALUES; i++) {
        values[i] = rand() % 101;
    }

    // 计算每个子进程需要处理的值的数量
    int values_per_child = NUM_VALUES / NUM_CHILDREN;

    // 为每个子进程创建一个管道
    int pipes[NUM_CHILDREN][2];
    for (int i = 0; i < NUM_CHILDREN; i++) {
        if (pipe(pipes[i]) == -1) {
            perror("pipe() error");
            exit(EXIT_FAILURE);
        }
    }

    // 创建4个子进程
    pid_t pid;
    for (int i = 0; i < NUM_CHILDREN; i++) {
        pid = fork();

        if (pid == -1) {
            perror("fork() error");
            exit(EXIT_FAILURE);
        } 
        else if (pid == 0) {
            // 在子进程中计算该进程需要处理的值的总和
            int start = i * values_per_child;
            int end = (i == NUM_CHILDREN - 1) ? NUM_VALUES : start + values_per_child;

            int sum = 0;
            for (int j = start; j < end; j++) {
                sum += values[j];
            }

            // 将该进程的计算结果写入管道
            close(pipes[i][0]);
            write(pipes[i][1], &sum, sizeof(sum));
            close(pipes[i][1]);

            exit(EXIT_SUCCESS);
        } 
    }

    // 等待4个子进程结束,并从管道中读取它们的计算结果
    int sum = 0;
    for (int i = 0; i < NUM_CHILDREN; i++) {
        int child_sum = 0;

        close(pipes[i][1]);
        read(pipes[i][0], &child_sum, sizeof(child_sum));
        close(pipes[i][0]);

        sum += child_sum;
        wait(NULL);
    }

    printf("Sum is: %d\n", sum);

    return 0;
}

在主进程中,我们做了以下几件事情:

  1. 生成1000个随机数;
  2. 计算每个子进程需要处理的值的数量;
  3. 为每个子进程创建一个管道;
  4. 创建四个子进程,并在每个子进程中计算该进程需要处理的值的总和;
  5. 等待四个子进程完成,并从管道中读取它们的计算结果;
  6. 将所有计算结果加和,并打印输出。
2. 子进程

根据主进程中的代码,我们可以看到在子进程中做了以下几件事情:

  1. 计算该进程需要处理的值的总和;
  2. 将该进程的计算结果写入管道;
  3. 退出子进程。

具体的实现代码为:

int start = i * values_per_child;
int end = (i == NUM_CHILDREN - 1) ? NUM_VALUES : start + values_per_child;

int sum = 0;
for (int j = start; j < end; j++) {
    sum += values[j];
}

// 将该进程的计算结果写入管道
close(pipes[i][0]);
write(pipes[i][1], &sum, sizeof(sum));
close(pipes[i][1]);

exit(EXIT_SUCCESS);

通过fork()函数,子进程从父进程中继承了父进程的所有变量和参数。在子进程中,我们计算该进程需要处理的值的总和,并将计算结果写入该进程所对应的管道中。

在计算完成后,我们调用了exit()函数,以结束子进程的程序执行。

3. 管道(pipe)

上面提到的管道(pipe),是一种用于进程间通信的机制。在本文的示例中,我们使用管道来传递子进程的计算结果给主进程。

管道由两个文件描述符组成:管道的读端和写端。一个进程可以向管道的写端写入数据,另一个进程可以从管道的读端读取数据。

管道的创建方法如下:

int pipefd[2];
if (pipe(pipefd) == -1) {
    perror("pipe() error");
    exit(EXIT_FAILURE);
}

创建管道时,系统会自动分配两个文件描述符给该管道,分别对应管道的读端和写端。我们可以使用这两个文件描述符,向管道中写入数据和从管道中读取数据。

4. wait()

在主进程中,我们使用wait()函数来等待子进程结束。wait()函数会在子进程结束后返回;如果子进程没有结束,wait()函数将一直阻塞,直到有子进程结束。

wait(NULL);

在本处理中,我们使用循环来等待所有子进程结束,因此我们在wait()函数中传递了一个NULL指针。如果我们想在子进程结束时获取子进程的退出状态,可以将一个指向整型变量的指针传递给wait()函数。这个整型变量将包含子进程的退出状态。

总结

本文介绍了如何使用fork()函数,在四个不同的进程中进行多次计算。通过使用fork()函数和管道机制,我们可以并行地处理大量的数据,以提高处理速度。

在实际编程中,我们需要考虑很多其他方面的因素,例如进程间同步、共享内存和避免死锁等问题。但是,使用fork()函数和管道来进行多进程编程,是解决许多大规模数据处理问题的重要手段。