使用fork()和pipe()将数字从1写入100

时间:2018-01-10 11:12:41

标签: c pipe fork ipc

我需要编写一个包含2个进程的程序,其中一个写入偶数,另一个写入不均匀的数字。在结果中,我必须按顺序从1到100。

我输入了这段代码,但是当涉及到处理部分时,它会卡在printProc()函数中。我想问题是在管道中读写。

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

int fd[2];

int printProc(int startNumber, int procNumber);

int main()
{
    pid_t childpid;

    pipe(fd);
    int start = 0;
    write(fd[0], &start, sizeof(start));

    if ((childpid = fork()) == -1)
    {
        perror("fork");
    }

    if (childpid == 0)
    {
        printf("run child\n");

        printProc(1, 0);
    }
    else
    {
        printf("run parent\n");

        printProc(2, 1);
    }

    return 0;
}

int printProc(int startNumber, int procNumber)
{
    FILE *f;
    f = fopen("output.txt", "a+");

    int num = startNumber;
    int proc;

    while (num <= 100)
    {
        read(fd[1], &proc, sizeof(proc));

        if (proc == procNumber)
        {
            fprintf(f, "%d", num);
            num = num + 2;
            proc = (proc + 1) % 2;
            write(fd[0], &proc, sizeof(proc));
        }
    }

    return 0;
}

3 个答案:

答案 0 :(得分:2)

我建议在这里使用互斥锁。您的关键部分将包含三个操作:

  • 检查是否轮到你写了
  • 如果满足以上条件,则写入输出
  • 如果您写信给输出,则表示轮到他的其他流程

以下是实现该目的的代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/mman.h>

int main() {
    pthread_mutex_t *pmutex;
    short * even;
    pthread_mutexattr_t attrmutex;

    pthread_mutexattr_init(&attrmutex);
    pthread_mutexattr_setpshared(&attrmutex, PTHREAD_PROCESS_SHARED);

    pmutex = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    even = mmap(NULL, sizeof(short), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    pthread_mutex_init(pmutex, &attrmutex);


    pthread_mutex_lock(pmutex);

    *even = 0;

    if(fork() == 0){
        int a = 2;

        while(a <= 100) {
            pthread_mutex_lock(pmutex);
            if(*even) {
                printf("%d\n", a);
                *even = 0;
                a = a + 2;
            }
            pthread_mutex_unlock(pmutex);
        }

        return 0;
    }else {
        int a = 1;

        printf("%d\n", a);
        *even = 1;
        pthread_mutex_unlock(pmutex);
        a = a + 2;
        while(a <= 99) {
            pthread_mutex_lock(pmutex);
            if(!*even) {
                printf("%d\n", a);
                *even = 1;
                a = a + 2;
            }
            pthread_mutex_unlock(pmutex);
        }

    }

    pthread_mutex_destroy(pmutex);
    pthread_mutexattr_destroy(&attrmutex);
}

两个进程共享两个变量:pmutex(用于同步)和even(用于检查允许打印的进程)。

答案 1 :(得分:1)

你需要2个管道,当一个进程写入数字时,它会将一些数据写入一个管道,这样另一个进程就会知道它可以编写自己的数字等。

实施的例子:

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

int main(void) {
  int parent_to_child[2];
  int child_to_parent[2];
  if (pipe(parent_to_child) == -1 || pipe(child_to_parent) == -1) {
    perror("pipe");
    return EXIT_FAILURE;
  }
  pid_t cpid = fork();
  if (cpid == -1) {
    perror("fork");
    return EXIT_FAILURE;
  }
  if (cpid == 0) {
    close(parent_to_child[1]);
    close(child_to_parent[0]);

    int i = 1;
    bool buf;
    ssize_t ret;
    while ((ret = read(parent_to_child[0], &buf, sizeof buf)) > 0) {
      fprintf(stdout, "%d ", i);
      fflush(stdout);
      if (write(child_to_parent[1], &buf, sizeof buf) != sizeof buf) {
        break;
      }
      i += 2;
    }

    close(parent_to_child[0]);
    close(child_to_parent[1]);
  } else {
    close(parent_to_child[0]);
    close(child_to_parent[1]);

    int i = 2;
    bool buf = true;
    ssize_t ret;
    while (i <= 100 &&
           write(parent_to_child[1], &buf, sizeof buf) == sizeof buf &&
           (ret = read(child_to_parent[0], &buf, sizeof buf)) > 0) {
      fprintf(stdout, i != 100 ? "%d " : "%d\n", i);
      fflush(stdout);
      i += 2;
    }

    close(parent_to_child[1]);
    close(child_to_parent[0]);
  }
}

答案 2 :(得分:1)

如果你想使用管道同步2个进程,你真的应该使用一对管道,前者由proc1读取并由proc2写入,后者由proc2读取并由proc1写入。从那里你将读写句柄传递给printProc,这就是全部。

但是代码中还有另一个问题:在缓冲模式下使用fopen)在两个进程中打开输出文件。所以每个进程都有自己的缓冲区。这两个缓冲区将被单独输入并且仅在关闭时写入文件,这不是您想要的:您必须在fork之前打开输出文件,并在非缓冲模式下使用它。

所以你的代码可能变成:

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


int printProc(int startNumber, FILE *f, int fdin, int fdout);

int main()
{
    pid_t childpid;
    int fd[4];
    FILE *f;

    pipe(fd);
    pipe(fd + 2);
    int start = 0;
    write(fd[0], &start, sizeof(start));
    f = fopen("output.txt", "w");
    if (f == NULL) {
        perror("Error opening file");
        return 1;
    }
    setbuf(f, NULL);             // use unbuffered mode for output.txt

    if ((childpid = fork()) == -1)
    {
        perror("fork");
    }

    if (childpid == 0)
    {
        printf("run child\n");

        printProc(1, f, fd[1], fd[2]);
    }
    else
    {
        printf("run parent\n");

        printProc(2, f, fd[3], fd[0]);
    }
    fclose(f);
    return 0;
}

int printProc(int num, FILE *f, int fdin, int fdout)
{
    int proc;

    while (num <= 100)
    {
        read(fdin, &proc, sizeof(proc));

        fprintf(f, "%d\n", num);
        num = num + 2;
        write(fdout, &proc, sizeof(proc));
    }
    return 0;
}