正确的fork()和pipe()用于具有多个子项的单个父项。 我该如何解决这个问题?

所以,我以前的post被标记为脱离主题,太模糊,并要求有用的代码的意见和build议。 它做了这些事情,所以我重新张贴作为我正在工作的代码的问题。 感谢上一篇文章中的内容,通过回顾你们所说的话,我能够把我在这里所得到的结果分解开来。

这里的重点是父/子关系和使用fork()和pipe()来获得所需的影响。

该项目是一个POSIX纸牌游戏,父母(经销商)从父母手中分出5个孩子(玩家)和自己的pipe道。 父母向玩家发牌(至less5卡),直到一个玩家拥有3个(不丢弃)。 获胜的孩子将获胜的手和EOF(退出(0))传送给父母以宣告胜利。 这会触发父母打印胜出的玩家,并将EOF传送给其余的孩子将其closures(退出(1))。 父母然后closures。 如果父母没有获胜者到达甲板的末端,则将EOF传递给孩子,等待他们退出(1)…然后closures。

我所面临的主要问题是孩子的程序如何分别读取每张卡片,而不是一遍又一遍地从pipe道读取相同的值。 我想我缺less一种方法来同步父母写入pipe道和孩子从pipe道读取。

我对这个家伙是全新的,所以任何帮助都非常感激。 非常感谢。

代码更新:(编译很多问题)完成和编译,但我显然有pipe道和通过它们传递数据的麻烦。 没有玩游戏,没有读取或写入pipe道,离开僵尸进程,这里是错误的。 我很感激任何投入在我的混乱。 大声笑

这是我运行程序(play.c)时的输出:

os@debian:~/Documents/cpsc351/projects/assn2$ gcc -o play play.c os@debian:~/Documents/cpsc351/projects/assn2$ ./play Pipe Success...toChild 1 created. Pipe Success...toParent 1 created. Pipe Success...toChild 2 created. Pipe Success...toParent 2 created. Pipe Success...toChild 3 created. Pipe Success...toParent 3 created. Pipe Success...toChild 4 created. Pipe Success...toParent 4 created. Pipe Success...toChild 5 created. Pipe Success...toParent 5 created. Parent: All players are at the table. Dealing cards... 30 5C to player 1 51 KS to player 2 9 10H to player 3 25 KD to player 4 6 7H to player 5 18 6D to player 1 45 7S to player 2 29 4C to player 3 37 QC to player 4 12 KH to player 5 7 8H to player 1 19 7D to player 2 20 8D to player 3 49 JS to player 4 35 10C to player 5 15 3D to player 1 5 6H to player 2 36 JC to player 3 0 AH to player 4 22 10D to player 5 48 10S to player 1 27 2C to player 2 42 4S to player 3 16 4D to player 4 32 7C to player 5 4 5H to player 1 14 2D to player 2 41 3S to player 3 39 AS to player 4 1 2H to player 5 26 AC to player 1 46 8S to player 2 34 9C to player 3 11 QH to player 4 24 QD to player 5 17 5D to player 1 31 6C to player 2 44 6S to player 3 40 2S to player 4 3 4H to player 5 21 9D to player 1 50 QS to player 2 13 AD to player 3 33 8C to player 4 23 JD to player 5 43 5S to player 1 2 3H to player 2 28 3C to player 3 47 9S to player 4 38 KC to player 5 10 JH to player 1 8 9H to player 2 Child: Fork Success...Player 4 is sitting at the table. Child: Player 4 is dealt a KD. Hand Total = 1 cards. Child: Player 4 is dealt a QC. Hand Total = 2 cards. Child: Player 4 is dealt a JS. Hand Total = 3 cards. Child: Player 4 is dealt a AH. Hand Total = 4 cards. Child: Player 4 is dealt a 4D. Hand Total = 5 cards. Child: Player 4 is dealt a AS. Hand Total = 6 cards. Child: Player 4 is dealt a QH. Hand Total = 7 cards. Child: Player 4 is dealt a 2S. Hand Total = 8 cards. Child: Player 4 is dealt a 8C. Hand Total = 9 cards. Child: Player 4 is dealt a 9S. Hand Total = 10 cards. Child: Fork Success...Player 5 is sitting at the table. Child: Player 5 is dealt a 7H. Hand Total = 1 cards. Child: Player 5 is dealt a KH. Hand Total = 2 cards. Child: Player 5 is dealt a 10C. Hand Total = 3 cards. Child: Player 5 is dealt a 10D. Hand Total = 4 cards. Child: Player 5 is dealt a 7C. Hand Total = 5 cards. Child: Player 5 is dealt a 2H. Hand Total = 6 cards. Child: Player 5 is dealt a QD. Hand Total = 7 cards. Child: Player 5 is dealt a 4H. Hand Total = 8 cards. Child: Player 5 is dealt a JD. Hand Total = 9 cards. Child: Player 5 is dealt a KC. Hand Total = 10 cards. Child: Player 5 has left the table. os@debian:~/Documents/cpsc351/projects/assn2$ Child: Player 4 has left the table. Child: Fork Success...Player 3 is sitting at the table. Child: Player 3 is dealt a 10H. Hand Total = 1 cards. Child: Player 3 is dealt a 4C. Hand Total = 2 cards. Child: Player 3 is dealt a 8D. Hand Total = 3 cards. Child: Player 3 is dealt a JC. Hand Total = 4 cards. Child: Player 3 is dealt a 4S. Hand Total = 5 cards. Child: Player 3 is dealt a 3S. Hand Total = 6 cards. Child: Player 3 is dealt a 9C. Hand Total = 7 cards. Child: Player 3 is dealt a 6S. Hand Total = 8 cards. Child: Player 3 is dealt a AD. Hand Total = 9 cards. Child: Player 3 is dealt a 3C. Hand Total = 10 cards. Child: Player 3 has left the table. Child: Fork Success...Player 2 is sitting at the table. Child: Player 2 is dealt a KS. Hand Total = 1 cards. Child: Player 2 is dealt a 7S. Hand Total = 2 cards. Child: Player 2 is dealt a 7D. Hand Total = 3 cards. Child: Player 2 is dealt a 6H. Hand Total = 4 cards. Child: Player 2 is dealt a 2C. Hand Total = 5 cards. Child: Player 2 is dealt a 2D. Hand Total = 6 cards. Child: Player 2 is dealt a 8S. Hand Total = 7 cards. Child: Player 2 is dealt a 6C. Hand Total = 8 cards. Child: Player 2 is dealt a QS. Hand Total = 9 cards. Child: Player 2 is dealt a 3H. Hand Total = 10 cards. Child: Player 2 is dealt a 9H. Hand Total = 11 cards. Child: Player 2 has left the table. Child: Fork Success...Player 1 is sitting at the table. Child: Player 1 is dealt a 5C. Hand Total = 1 cards. Child: Player 1 is dealt a 6D. Hand Total = 2 cards. Child: Player 1 is dealt a 8H. Hand Total = 3 cards. Child: Player 1 is dealt a 3D. Hand Total = 4 cards. Child: Player 1 is dealt a 10S. Hand Total = 5 cards. Child: Player 1 is dealt a 5H. Hand Total = 6 cards. Child: Player 1 is dealt a AC. Hand Total = 7 cards. Child: Player 1 is dealt a 5D. Hand Total = 8 cards. Child: Player 1 has at least "3 of a Kind". Hand Total = 8 cards. 

当前代码:

 #define _POSIX_C_SOURCE 200809L #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include "cards.h" #include "cards.c" #define READ 0 #define WRITE 1 #define PLAYERS 5 int main(int argc, char *argv[]) { //loop declarations ***Would not let me initialize within a for-loop...c99 error.*** int i; int j; pid_t player[PLAYERS]; int toChild_pipe[PLAYERS][2]; int toParent_pipe[PLAYERS][2]; int dealt_card; int card_count = 1; int player_count = 0; int status_forChild; int status_forParent; int player_card; for(i = 0; i < PLAYERS; i++) { // Create the pipes if (pipe(toChild_pipe[i]) < 0) { perror("'To-Child' Pipe Error\n"); exit(1); } if (pipe(toParent_pipe[i]) < 0) { perror("'To-Parent' Pipe Error\n"); exit(1); } // Fork the child (new player) player[i] = fork(); if (player[i] < 0) { perror("Fork Error:"); printf(" Player %d cloud not sit at table.\n", i+1); exit(1); } else if (player[i] > 0) //Parent Process { // Close unsed pipe ends in Parent close(toChild_pipe[i][READ]); close(toParent_pipe[i][WRITE]); } else //(player[i] == 0)-- Child Process { int player_num = (i+1); int player_card; int hand[13] = {0}; int player_card_count = 0; bool game_over = false; printf("Child: Fork Success...Player %d is sitting at the table.\n", player_num); // Close unsed pipe ends in Parent close(toParent_pipe[i][READ]); close(toChild_pipe[i][WRITE]); while(!game_over) { if ((status_forChild = read(toChild_pipe[i][READ], &player_card, sizeof(player_card))) == 0) { //EOF from parent. Player lost. game_over = true; close(toParent_pipe[i][WRITE]); close(toChild_pipe[i][READ]); printf("Child: Player %d has left the table.\n", player_num); exit(1); } else if (status_forChild == -1) { perror(""); printf("Child %d: ERROR: Could not read from pipe.\n", i+1); exit(1); } else { //Players have 5 cards, loop through hand to check for winner. If yes, WIN. if (player_card_count == 5) { for (j = 0; j < 13; j++) { if(hand[j] >=3) { //WINNER! Close process (status = 0) printf("Child: Player %d has at least. Hand Total = %d cards.\n" , player_num, rank(player_card)); close(toParent_pipe[i][WRITE]); close(toChild_pipe[i][READ]); exit(0); } } } //Read the current card value dealt, increment card value in hand array int card_index = value_index(rank(player_card)); hand[card_index]++; player_card_count++; printf("Child: Player %d is dealt a %s%s. Hand Total = %d cards.\n", player_num, rank(player_card), suit(player_card), player_card_count); if ((hand[card_index] >= 3)&&(player_card_count > 5)) //at least (3 of a kind) and (> 5 card hand) { //WINNER! Close process (status = 0) printf("Child: Player %d has at least. Hand Total = %d cards.\n", player_num, rank(player_card)); close(toParent_pipe[i][WRITE]); close(toChild_pipe[i][READ]); exit(0); } } } } } shuffle(); printf("Parent: All players are at the table. Dealing cards... \n"); while ((dealt_card = deal()) != EOF) { //Card is written to the pipe for current player if ((status_forParent = write(toChild_pipe[i][WRITE], &dealt_card, sizeof(dealt_card))) == -1) { perror(""); printf("Parent: ERROR: Could not read from pipe for Child %d.\n", i+1); exit(1); } //If child process exited with status = 0, child had 3 of a kind and wins game. else if (status_forParent == 0) { printf("Parent: Player %d has WON!!!\n", player_count+1, rank(player_card)); break; } else { printf(" %d %s%s to player %d\n", dealt_card, rank(dealt_card), suit(dealt_card), player_count+1); if (player_count >= PLAYERS-1) player_count = 0; else player_count++; } } // Close pipe ends close(toParent_pipe[i][READ]); close(toChild_pipe[i][WRITE]); wait(NULL); return 0; } 

Solutions Collecting From Web of "正确的fork()和pipe()用于具有多个子项的单个父项。 我该如何解决这个问题?"

你有的基本问题是你依靠EOF来检测事物,但是直到管道的写入结束的所有句柄都关闭之后才会发生EOF。 所以你必须小心地关闭所有进程中不需要的句柄。

在你的代码中,你有一个创建管道的循环,然后分叉:

  • 首先为子0创建两个管道
  • 然后叉子0
  • 子0关闭这些管道的父节点,而父节点关闭那些管道的子节点(好)
  • 循环
  • 为子1创建两个管道
  • 叉子1
  • 子1关闭其管道的父节点,而父节点关闭子节点。

在这一点上,你有一个问题 – 子1已经将管道的父节点继承到子节点0,但没有关闭它们。 这意味着孩子0从父母读取时将无法检测到EOF。 孩子2和以后的孩子也会发生同样的事情。

这种类似于代码的答案,但不是真的,因为代码中的注释解释了发生了什么。 这不是你正在写的游戏,而是显示你正在寻找的机制。 您可以根据您的具体情况调整这种框架。

码:

 /* Demonstration of multiplayer "game" with processes. * * The parent sets up a number of processes equal to NUM_KIDS. * It loops through each one in turn, and writes a character to * each child, beginning with one. The child reads it, and if * that character is the winning number, it writes back to the * parent to notify it, and exits. If it's not the winning * character, it writes a different character to the parent (which * is ignored) and waits for another character to read. If it * reads the game over character, it exits. * * It's not a very fun game, but demonstrates how a number of * child processes can act as different players, how they can * receive input from the parent and, based on that input, how * they can determine a win situation and notify the parent of * such. */ #define _POSIX_C_SOURCE 200809L #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #define NUM_KIDS 5 static const int CHILD_NO_WIN = 0; /* Child sends this if it doesnt win */ static const int CHILD_WIN = 1; /* Child sends this if it wins */ static const int GAME_OVER = 0; /* Child loses if it receives this */ static const int WINNER = 13; /* Child wins if it receives this */ /* Convenience function to make a pair of pipes */ void make_pipe_pair(int * pair1, int * pair2) { if ( pipe(pair1) == -1 || pipe(pair2) == -1 ) { perror("couldn't create pipe"); exit(EXIT_FAILURE); } } /* Convenience function to close a pair of file descriptors */ void close_pair(const int rfd, const int wfd) { if ( close(rfd) == -1 || close(wfd) == -1 ) { perror("couldn't close file"); exit(EXIT_FAILURE); } } /* Main child process function */ void child_func(const int rpipe, const int wpipe, const size_t child_id) { char out_c = CHILD_NO_WIN; /* Character to write */ char in_c; /* Character to read */ bool keep_reading = true; while ( keep_reading ) { /* Read a single character from the parent */ ssize_t num_read; if ( (num_read = read(rpipe, &in_c, 1)) == -1 ) { perror("error reading from pipe in child"); exit(EXIT_FAILURE); } else if ( num_read == 0 ) { printf("Pipe from parent closed to child %zu.\n", child_id); keep_reading = false; } else { printf("Child %zu read %d from parent.\n", child_id, in_c); if ( in_c == GAME_OVER ) { /* We lost, so tell loop to end. No need to write() * to parent, since it already knows a previous * child won. */ printf("Child %zu got game over signal.\n", child_id); keep_reading = false; } else { if ( in_c == WINNER ) { /* We won, so send won signal to parent */ out_c = 1; } /* Write won signal to parent if we won, or * other character if we didn't. */ if ( write(wpipe, &out_c, 1) == -1 ) { perror("error writing to pipe in child"); exit(EXIT_FAILURE); } else { printf("Child %zu wrote %d to parent.\n", child_id, out_c); } } } } /* Close file descriptors and exit */ close_pair(rpipe, wpipe); } /* Main function */ int main(void) { int ptoc_fd[NUM_KIDS][2]; /* Parent to child pipes */ int ctop_fd[NUM_KIDS][2]; /* Child to parent pipes */ pid_t children[NUM_KIDS]; /* Process IDs of children */ int winning_child; /* Holds number of winner */ /* Create pipe pairs and fork children */ for ( size_t i = 0; i < NUM_KIDS; ++i ) { make_pipe_pair(ptoc_fd[i], ctop_fd[i]); if ( (children[i] = fork()) == -1 ) { perror("error calling fork()"); return EXIT_FAILURE; } else if ( children[i] == 0 ) { printf("Child %zu created.\n", i + 1); close_pair(ctop_fd[i][0], ptoc_fd[i][1]); child_func(ptoc_fd[i][0], ctop_fd[i][1], i + 1); printf("Child %zu terminating.\n", i + 1); return EXIT_SUCCESS; } else { close_pair(ptoc_fd[i][0], ctop_fd[i][1]); } } /* Set up game variables and enter main loop */ char out_c = 1; char in_c = 0; bool won = false; while ( !won ) { /* Loop through each child */ for ( size_t i = 0; !won && i < NUM_KIDS; ++i ) { /* Write next number to child */ if ( write(ptoc_fd[i][1], &out_c, 1) == -1 ) { perror("error writing to pipe"); exit(EXIT_FAILURE); } else { printf("Parent wrote %d to child %zu.\n", out_c, i+1); } ++out_c; /* Read status from child if game not over */ if ( !won ) { ssize_t num_read; if ( (num_read = read(ctop_fd[i][0], &in_c, 1)) == -1 ) { perror("error reading from pipe"); return EXIT_FAILURE; } else if ( num_read == 0 ) { printf("Pipe from child %zu closed.\n", i+1); } else { printf("Parent read %d from child %zu.\n", in_c, i+1); if ( in_c == CHILD_WIN ) { printf("Parent got won signal from child %zu.\n", i+1); won = true; winning_child = i+1; } } } } } /* Clean up and harvest dead children */ out_c = 0; for ( size_t i = 0; i < NUM_KIDS; ++i ) { if ( write(ptoc_fd[i][1], &out_c, 1) == -1 ) { perror("error writing to pipe"); exit(EXIT_FAILURE); } else { printf("Parent wrote %d to child %zu.\n", out_c, i + 1); } if ( waitpid(children[i], NULL, 0) == -1 ) { perror("error calling waitpid()"); return EXIT_FAILURE; } else { printf("Successfully waited for child %zu.\n", i + 1); } close_pair(ptoc_fd[i][1], ctop_fd[i][0]); } /* Show who won, and then quit. */ printf("Parent terminating. Child %d won.\n", winning_child); return EXIT_SUCCESS; } 

和输出:

 paul@thoth:~/src/sandbox/multipipe$ ./multipipe Child 1 created. Child 1 read 1 from parent. Parent wrote 1 to child 1. Child 1 wrote 0 to parent. Child 3 created. Parent read 0 from child 1. Parent wrote 2 to child 2. Child 2 created. Child 2 read 2 from parent. Parent read 0 from child 2. Parent wrote 3 to child 3. Child 3 read 3 from parent. Parent read 0 from child 3. Child 4 created. Parent wrote 4 to child 4. Child 3 wrote 0 to parent. Child 2 wrote 0 to parent. Child 4 read 4 from parent. Child 5 created. Parent read 0 from child 4. Parent wrote 5 to child 5. Child 4 wrote 0 to parent. Child 5 read 5 from parent. Parent read 0 from child 5. Parent wrote 6 to child 1. Child 5 wrote 0 to parent. Child 1 read 6 from parent. Parent read 0 from child 1. Parent wrote 7 to child 2. Child 1 wrote 0 to parent. Child 2 read 7 from parent. Parent read 0 from child 2. Parent wrote 8 to child 3. Child 3 read 8 from parent. Parent read 0 from child 3. Child 2 wrote 0 to parent. Parent wrote 9 to child 4. Child 4 read 9 from parent. Parent read 0 from child 4. Parent wrote 10 to child 5. Child 3 wrote 0 to parent. Child 4 wrote 0 to parent. Child 5 read 10 from parent. Child 5 wrote 0 to parent. Parent read 0 from child 5. Parent wrote 11 to child 1. Child 1 read 11 from parent. Parent read 0 from child 1. Parent wrote 12 to child 2. Child 2 read 12 from parent. Child 1 wrote 0 to parent. Parent read 0 from child 2. Parent wrote 13 to child 3. Child 3 read 13 from parent. Parent read 1 from child 3. Parent got won signal from child 3. Parent wrote 0 to child 1. Child 2 wrote 0 to parent. Child 1 read 0 from parent. Child 1 got game over signal. Child 1 terminating. Child 3 wrote 1 to parent. Successfully waited for child 1. Parent wrote 0 to child 2. Child 2 read 0 from parent. Child 2 got game over signal. Child 2 terminating. Successfully waited for child 2. Parent wrote 0 to child 3. Child 3 read 0 from parent. Child 3 got game over signal. Child 3 terminating. Successfully waited for child 3. Parent wrote 0 to child 4. Child 4 read 0 from parent. Child 4 got game over signal. Child 4 terminating. Successfully waited for child 4. Parent wrote 0 to child 5. Child 5 read 0 from parent. Child 5 got game over signal. Child 5 terminating. Successfully waited for child 5. Parent terminating. Child 3 won. paul@thoth:~/src/sandbox/multipipe$ 

输出看起来有点奇怪,看起来好像进程在被写入之前正在读取东西,但是当您使用异步进程时,会发生这种情况,并且不会为了演示目的而同步输入/输出。 对管道的实际读写操作是很好的,并且是同步的,只是调试信息转到标准输出,看起来很棘手。 你应该仍然能够看到发生了什么事情。