c - fork() 和 pipeline() 的竞争条件

标签 c concurrency ipc race-condition

我正在为一项作业编写一个程序,其中父进程将四个子进程与 N 个子进程进行连接。该程序使用管道在进程之间传递游戏 Action 。

但是,我在修复程序中存在的竞争条件时遇到问题。有一种情况是子进程在游戏结束后挂起其 read() 调用。似乎只有当有多个子进程时才会发生这种情况。

我已经尝试过一些东西,例如命名信号量,但我对 fork 、管道和 IPC 仍然很陌生。我在这里发布了包含相关代码的要点(我尝试尽可能地清理它以提高可读性):

<强> Gist with relevant code

任何帮助将不胜感激

编辑

这是要点中的相关来源,并添加了声明。

int main (int argc, char const *argv[])
{
  int dimension = 8, children = 2, i;
  int child_play_to_win = 0;
  int fd[children][4];
  pid_t childpid[children];
  Board** boards = (Board**) malloc(sizeof(Board*) * children);
  GameMove* lastMove, *tmpMove;
  char buf[80];
  for(i = 0; i < children; i++) {
     generate_board(&(boards[i]), dimension);
     int tmp[2];
     pipe(tmp);

    // child read
    fd[i][0] = dup(tmp[0]);
    // parent write
    fd[i][1] = dup(tmp[1]);

    pipe(tmp);
    // parent read
    fd[i][2] = dup(tmp[0]);
    // child write
    fd[i][3] = dup(tmp[1]);

        childpid[i] = fork();

    if(childpid[i] == -1) {
        perror("fork");
        exit(1);
    }
    if(childpid[i] == 0) {
      srand(getpid());
      close(fd[i][1]);
      close(fd[i][2]);
      while(!boards[i]->finished) {
        // Read in move from parent
        printf("child[%d] about to read\n", getpid());
        read(fd[i][0], &buf, sizeof(GameMove));

        // repeat parent move on this board

        if(gameNotFinished) {
          // make child move

          // write move back to parent

          write(fd[i][3], lastMove, sizeof(GameMove));

          // If the board is finished (there was a win),
          if (!gameNotFinihsed) {
            // Child wins
            close(fd[i][0]);
            close(fd[i][3]);
            printf("child[%d] ending\n", getpid()); 
            break;
          }
        }
        else {
          // Parent won
          close(fd[i][0]);
          close(fd[i][3]);
          break;
        } 
      }
    dealloc(boards[i]);
    exit(0);
    }
}

  // When this hits children amount, all games are done
  int games_complete = 0;
  // Make first move to all children
  for (i = 0; i < children; i++) {
    close(fd[i][0]);
    close(fd[i][3]);
    lastMove = placePieceAtBestPosition(boards[i], 1);
    printf("parent writing to child[%d]\n", childpid[i]);
    write(fd[i][1], lastMove, sizeof(GameMove));
  }
  while (games_complete != children) {
    for (i = 0; i < children; i++) {
      // Read move from child
      read(fd[i][2], &buf, sizeof(GameMove));

      // repeat child move

      // Check for a child win...
      if (!checkForWin(boards[i], 2)) {
        // No win yet, place piece at best position

        lastMove = placePieceAtBestPosition(boards[i], 1);

        // check for win again
        boards[i]->finished = checkForWin(boards[i], 1);
        // Write move back to child
        write(fd[i][1], lastMove, sizeof(GameMove));

        // If we won, close everything up and increment
        // the games_complete counter.
        if(boards[i]->finished) {
          close(fd[i][1]);
          close(fd[i][2]);
          games_complete++;
        }
      } else {
    // write back child move if there was a win
        write(fd[i][1], lastMove, sizeof(GameMove));
        close(fd[i][1]);
        close(fd[i][2]);
        printf("Parent lost! ):\n");
        games_complete++;
      }
    }
  }

最佳答案

我想我知道你的问题是什么。当您 fork 每个子项时,您将关闭其管道的父项。然而,每个 child 仍然为所有先前的 child 打开管道的父端。因此,只有最后创建的子级才会关闭其管道的父级端。

建议你改变:

close(fd[i][1]);
close(fd[i][2]);

类似:

for (j = 0; j <=i; j++) {
  close(fd[j][1]);
  close(fd[j][2]);
}

关于c - fork() 和 pipeline() 的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15254909/

相关文章:

c - [C] 中的预处理器

python - 为什么 asyncio.Future 与 concurrent.futures.Future 不兼容?

Java类: How would I make a class that returns a string parameter but can also be used as an entry point for an application?

c++ - "printf"在 Windows 非控制台应用程序中写在哪里?

c - gtk_container_get_children

c - 使用线程时出现段错误 - c

java - 具有多个消费者的生产者因notify()而失败

java - 当其中一个找到素数时如何停止线程

c# - IPC 使用 Protobuf 和内存映射文件 C#

c++ - 我可以使用内存映射文件传递指针吗?