C, getting a parent and child process to work using signals
我正试图让我的子进程生成一个介于1 -9之间的随机数,然后将其发送给我的父进程,每次按下控件Z时,它将显示在屏幕上。我还使用dup2()将流从printf和scanf更改为每个进程的管道的读取和写入端。
该代码的工作原理如下,按C键启动主程序。现在,每次从子级发送一个随机数并将其显示在父级时,它都等待按下控件Z。我面临的问题是,似乎再次按下控件Z时,子级只运行一次,它仅运行父代代码。管道也只会显示相同的编号,并且永远不会更改,因此不会被更新。我还注意到,如果我在dup函数printf(" a \\\\
"),它会打印出随机数。...但是,子运行一次的问题仍然存在。
如果有人可以帮助我,我将不胜感激。干杯。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | #include <stdio.h> #include <signal.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <string.h> #include <stdlib.h> int selection = 0; int secondSel = 0; int fd[2]; int pipe1; pid_t fork1; void handleSignal(int sig) { if (sig == SIGINT) { selection = 1; secondSel = 1; } if (sig == SIGTSTP) { selection = 1; } } int main() { int firstPipe[2]; int secondPipe[2]; //wait for control+C if (signal(SIGINT, handleSignal) == SIG_ERR) { printf("Error catching signal C \ "); exit(0); } while(1) { //wait till control c is pressed if (selection == 1) { signal(SIGINT, SIG_IGN); if (secondSel == 1) { pipe1 = pipe(fd); } if (pipe1 < 0) { printf("Error creating pipe 1 \ "); exit(1); } if (secondSel == 1) { fork1 = fork(); } if (fork1 < 0) { printf("Error with first fork. \ "); exit(1); } else if (fork1 == 0) //first child process { signal(SIGTSTP, handleSignal); pause(); printf("a \ "); int randNum1; close(fd[0]); dup2(fd[1], 1); randNum1 = rand() % 9 + 1; printf("%d", randNum1); fflush(stdout); close(fd[1]); } else //parent { signal(SIGTSTP, handleSignal); pause(); printf("b \ "); int f; close(fd[1]); dup2(fd[0], 0); scanf("%d \ ", &f); printf("%d \ ", f); close(fd[0]); } secondSel = 0; } } } |
注释/代码:
1 2 | //wait for control+C if (signal(SIGINT, handleSignal) == SIG_ERR) |
是一个令人不安的开始。
在无限循环内,代码:
1 2 3 4 5 6 7 8 9 10 |
是次优的和/或令人困惑的。由于仅在调用
1 2 3 4 5 6 7 8 9 |
对保护
您的代码在第一个循环后会仔细关闭管道,但永远不要重新打开它。最终,这就是第二次和后续迭代失败的原因。如果您不尝试在每个周期中做所有事情,那么您的代码会更好。另外,使用标准输出来调试信息会遇到各种问题。最好改用标准错误-尤其是在标准输出不能正常工作的情况下。
插装代码
这是代码的检测版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> static void err_syserr(const char *fmt, ...); int selection = 0; int secondSel = 0; int fd[2]; int pipe1 = 0; pid_t fork1 = 0; static void handleSignal(int sig) { if (sig == SIGINT) { selection = 1; secondSel = 1; } if (sig == SIGTSTP) { selection = 1; } } int main(void) { // wait for control+C if (signal(SIGINT, handleSignal) == SIG_ERR) { printf("Error catching signal C\ "); exit(1); } //printf("Waiting for interrupt\ "); //pause(); while (1) { fprintf(stderr,"Looping: %d (%d)\ ", (int)getpid(), selection); // wait till control c is pressed if (selection == 1) { signal(SIGINT, SIG_IGN); if (secondSel == 1) { pipe1 = pipe(fd); fprintf(stderr,"Created pipe: %d (%d, %d)\ ", pipe1, fd[0], fd[1]); } if (pipe1 < 0) { printf("Error creating pipe 1\ "); exit(1); } if (secondSel == 1) { fork1 = fork(); fprintf(stderr,"Forked: %d (%d, %d)\ ", fork1, (int)getpid(), (int)getppid()); } if (fork1 < 0) { printf("Error with first fork.\ "); exit(1); } else if (fork1 == 0) // first child process { signal(SIGTSTP, handleSignal); fprintf(stderr,"Pausing C: %d\ ", (int)getpid()); pause(); fprintf(stderr,"Unpaused C: %d\ ", (int)getpid()); printf("a\ "); if (close(fd[0]) != 0) err_syserr("close(fd[0]=%d) failed", fd[0]); if (dup2(fd[1], 1) < 0) err_syserr("dup2(fd[1]=%d, 1) failed", fd[1]); int randNum1 = rand() % 9 + 1; fprintf(stderr,"Print C: %d\ ", randNum1); if (printf("%d\ ", randNum1) < 2) { fprintf(stderr,"Print C: failed\ "); clearerr(stdout); } fflush(stdout); if (close(fd[1]) != 0) err_syserr("close(fd[1]=%d) failed", fd[1]); } else // parent { signal(SIGTSTP, handleSignal); fprintf(stderr,"Pausing P: %d\ ", (int)getpid()); pause(); fprintf(stderr,"Unpaused P: %d\ ", (int)getpid()); printf("b\ "); if (close(fd[1]) != 0) err_syserr("close(fd[1]=%d) failed", fd[1]); if (dup2(fd[0], 0) < 0) err_syserr("dup2(fd[0]=%d, 0) failed", fd[0]); int f = 99; if (scanf("%d", &f) != 1) { fprintf(stderr,"Scanf P: failed\ "); clearerr(stdin); } printf("Parent: %d\ ", f); if (close(fd[0]) < 0) err_syserr("close(fd[0]=%d) failed", fd[0]); } secondSel = 0; } } return 0; } #include <errno.h> #include <string.h> #include <stdarg.h> static void err_syserr(const char *fmt, ...) { int errnum = errno; va_list args; if (fork1 != 0) /* Parent waits 1/4 second */ usleep(250000); fprintf(stderr,"%d:", (int)getpid()); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); if (errnum != 0) fprintf(stderr,": %d %s", errnum, strerror(errnum)); fputc('\ ', stderr); exit(EXIT_FAILURE); } |
示例输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | $ ./sigbug Looping: 23528 (0) Looping: 23528 (0) … …huge numbers of 'looping' messages omitted… … Looping: 23528 (0) Looping: 23528 (0) Looping: 23528 (0) Looping: 23528 (0) ^CLooping: 23528 (0) Looping: 23528 (0) Looping: 23528 (0) Looping: 23528 (0) Created pipe: 0 (3, 4) Forked: 23529 (23528, 45428) Pausing P: 23528 Forked: 0 (23529, 23528) Pausing C: 23529 ^ZUnpaused C: 23529 Unpaused P: 23528 a b Print C: 5 Looping: 23529 (1) Pausing C: 23529 Parent: 5 Looping: 23528 (1) Pausing P: 23528 ^ZUnpaused P: 23528 b Unpaused C: 23529 23529: close(fd[0]=3) failed: 9 Bad file descriptor 23528: close(fd[1]=4) failed: 9 Bad file descriptor $ |
错误修正代码
这是代码的修订版,在我看来似乎更合适。它不包含
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> static void handleSignal(int sig) { return; } int main(void) { int fd[2]; int pipe1 = 0; pid_t fork1 = 0; if (signal(SIGINT, handleSignal) == SIG_ERR) { printf("Error catching signal C\ "); exit(1); } printf("Waiting for interrupt\ "); pause(); signal(SIGINT, SIG_IGN); pipe1 = pipe(fd); if (pipe1 < 0) { fprintf(stderr,"Error creating pipe 1\ "); exit(1); } fprintf(stderr,"Created pipe: %d (%d, %d)\ ", pipe1, fd[0], fd[1]); fork1 = fork(); if (fork1 < 0) { fprintf(stderr,"Error with fork.\ "); exit(1); } fprintf(stderr,"Forked: %d (%d, %d)\ ", fork1, (int)getpid(), (int)getppid()); signal(SIGTSTP, handleSignal); if (fork1 == 0) { dup2(fd[1], 1); close(fd[0]); close(fd[1]); while (1) { fprintf(stderr,"Pausing C: %d\ ", (int)getpid()); pause(); fprintf(stderr,"Unpaused C: %d\ ", (int)getpid()); int randNum1 = rand() % 9 + 1; fprintf(stderr,"Print C: %d\ ", randNum1); if (printf("%d\ ", randNum1) < 2) { fprintf(stderr,"Print C: failed\ "); clearerr(stdout); } fflush(stdout); } } else { dup2(fd[0], 0); close(fd[0]); close(fd[1]); while (1) { fprintf(stderr,"Pausing P: %d\ ", (int)getpid()); pause(); fprintf(stderr,"Unpaused P: %d\ ", (int)getpid()); int f = 99; if (scanf("%d", &f) != 1) { fprintf(stderr,"Scanf P: failed\ "); clearerr(stdin); } else printf("Parent: %d\ ", f); } } return 0; } |
示例输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | $ ./sigbug-jl1 Waiting for interrupt ^CCreated pipe: 0 (3, 4) Forked: 23554 (23553, 45428) Pausing P: 23553 Forked: 0 (23554, 23553) Pausing C: 23554 ^ZUnpaused C: 23554 Print C: 5 Unpaused P: 23553 Pausing C: 23554 Parent: 5 Pausing P: 23553 ^ZUnpaused C: 23554 Print C: 8 Unpaused P: 23553 Pausing C: 23554 Parent: 8 Pausing P: 23553 ^ZUnpaused P: 23553 Unpaused C: 23554 Print C: 6 Pausing C: 23554 Parent: 6 Pausing P: 23553 ^\\Quit: 3 $ |
由于禁止了中断,因此我使用SIGQUIT终止了程序。
您遇到的问题是由于第一个数字从子级发送到父级后关闭了管道。
但是,主要问题是您的代码杂乱无章,这使得弄清楚正在发生的事情变得更加困难,并且增加了出错的机会。建议不要像下面那样重组所有代码,而不是将所有内容都放入一个大循环中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | wait for SIGINT create pipe fork if child: set up stdout using dup2() while true: wait for SIGTSTP write to pipe else: set up stdin using dup2() while true: wait for SIGTSTP read from pipe etc. |