c - fork 进程不是在 C 中调用函数

标签 c unix fork

这里是 C 初学者。函数 send_chars_to_reducers 似乎没有在 fork_mappers 函数中创建的 fork 进程中被调用。

C代码

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

#define BUFFER_SIZE 1024
#define ALPHA_OFFSET 97
#define LETTERS 26

const int NUM_OF_MAPPERS = 4;
const int NUM_OF_REDUCERS = 26;

const int PIPE_READ_END = 0;
const int PIPE_WRITE_END = 1;
const int PIPE_BUFFER_SIZE = 1000;

int mapper_pipes[4][2];
int reducer_pipes[26][2];

void pipe_wrapper(int pipefd[]) {
    int ret = pipe(pipefd);
    if (ret == -1) {
        perror("Error. Failed when trying to create pipes.");
        exit(EXIT_FAILURE);
    }
}

void create_mapper_pipes(void) {
    int i;
    for (i = 0; i < NUM_OF_MAPPERS; i++) {
        pipe_wrapper(mapper_pipes[i]);
    }
}

void create_reducer_pipes(void) {
    int i; 
    for (i=0; i < NUM_OF_REDUCERS; i++) {
        pipe_wrapper(reducer_pipes[i]);
    }
}

// Prints an error msg and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val, const char* syscall_name) {
    if (syscall_val < 0) {
        perror(syscall_name);
        exit(errno);
    } else {
        //No syscall error we can return
        return syscall_val;
    }
}

void send_chars_to_reducers(void) {
    printf("hello from send_chars_to_reducers\n");
}

void fork_mappers(void) {


    /* Constants useful to all children */
    char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
    int rlen = 0;

    int i;
    for (i=0; i<NUM_OF_MAPPERS; i++) {
        pid_t mapper_pid = print_if_err(fork(), "fork");
        close(mapper_pipes[i][PIPE_WRITE_END]);
        if (mapper_pid == 0) {
            rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
            while(rlen > 0) {    
                send_chars_to_reducers();
                printf("read line from forked_mappers, p%d: %s\n", i, ibuf);
                rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
            }
            _exit(0);
        }
    }
}

void fork_reducers(void) {
    printf("hello from fork_reducers\n"); 
    int i;
    for (i = 0; i < NUM_OF_REDUCERS; i++) {
        pid_t reducer_pid = print_if_err(fork(), "fork");
        if (reducer_pid == 0) {
            while (1 == 1) {

            }       
        }
    }
}

void send_lines_to_mappers(void) {
    int wlen = 0;
    char obuf[PIPE_BUFFER_SIZE];
    int ob_size;
    int count = 0;

    char buff[BUFFER_SIZE]; // a buffer for each line of the file
    FILE *input_file = fopen("input.txt", "r");
    // read the input file line by line
    while(fgets(buff, BUFFER_SIZE, input_file) > 0) {
        printf("read line from send_lin_to_mappers: %s\n", buff);
        ob_size = sizeof buff;
        switch(count) {
            case 0 :
                write(mapper_pipes[0][PIPE_WRITE_END], buff, ob_size);
                close(mapper_pipes[0][PIPE_WRITE_END]);
                break;
            case 1 : 
                write(mapper_pipes[1][PIPE_WRITE_END], buff, ob_size);
                close(mapper_pipes[1][PIPE_WRITE_END]);
                break;
            case 2 :
                write(mapper_pipes[2][PIPE_WRITE_END], buff, ob_size);
                close(mapper_pipes[2][PIPE_WRITE_END]);
                break;
            case 3 : 
                write(mapper_pipes[3][PIPE_WRITE_END], buff, ob_size);
                close(mapper_pipes[3][PIPE_WRITE_END]);
                break;
            default :
                printf("you did something wrong in send_lines_to_mappers loop");
        }
        count++;
    }
    fclose(input_file);
}

int main(void) {
    // Setup the mapper pipes
    create_mapper_pipes();
    create_reducer_pipes();
    fork_reducers();
    fork_mappers();
    send_lines_to_mappers();

    return 0;
}

输出

hello from fork_reducers
read line from send_lin_to_mappers: I like coding in C.

read line from send_lin_to_mappers: I like manually allocating memory, and opening the registers window in Visual Studio to see the values of the eax register and blitting graphics to the screen and all the stuff that Dr. Dobbs wrote about in the 90s.

read line from send_lin_to_mappers: My programming friends seem to believe that understanding this level of programming is good in a hand-wavy, theoretical sense, but when you consider all the web development, Java frameworks, and existing libraries most programmers today rely on, it's hard to really pin down a solid answer to the question "Why learn C?"

read line from send_lin_to_mappers: This is my attempt to answer that question, and I believe it comes down to the basic programming concept of abstraction.

最佳答案

问题在于共享句柄的进程数。 每个 reducer 都有管道打开 每个映射器都打开了管道,因此管道永远不会正确关闭(reducer 处于繁忙的循环中。

    if (mapper_pid == 0) {
      int j;
      for( j = 0; j < NUM_OF_MAPPERS; j++ ){
        close( mapper_pipes[j][PIPE_WRITE_END]);
        if( j != i ){
           close(mapper_pipes[j][PIPE_READ_END]);
        }
    }

我注释掉了 reducer fork,然后修复了 mapper fork 以关闭子项中的所有管道句柄,除了我们想要读取的那个。

这开始使程序运行。 来自 pipe documentation ,您应该关闭管道中未使用的部分。但是您已经预先打开了所有管道(可能更好地本地化它们),因此必须关闭子进程中所有未使用的句柄以使操作系统正确整理资源

关于c - fork 进程不是在 C 中调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35307208/

相关文章:

c - 父子进程打印

c - 如何从CHILD PROCESS中获取返回值?

c - 在C编程中对字符串与相应的整数数组进行排序

regex - 从查找中排除文件类型的正则表达式

android - 一个进程试图 chmod 一个文件,而另一个进程已经写入该文件?

shell - 在 scp 中使用别名而不是 IP

c - 如何用C代码编写shell '&'?

c - 为什么子进程在使用父输出的标准输入的 fork 和管道时等待?

c - 需要帮助理解这段 C 代码的作用

c - 崩数的情况下如何处理?