unix 仅用信号同步N进程

m1m5dgzv  于 2022-11-04  发布在  Unix
关注(0)|答案(1)|浏览(242)

我正在做一个操作系统课程的练习。为了学习使用信号(我的一个弱点),我想尝试只用信号同步N个进程。但是我做不到。
代码为:

  1. # include "Header.h"
  2. # include <signal.h>
  3. // first sigHandler
  4. void sigHandler(int signum)
  5. {
  6. printf("Received signal\n");
  7. }
  8. // second sigHandler
  9. void sigHandler2(int signum)
  10. {
  11. printf("Received other signal\n");
  12. }
  13. int main(int argc, char *argv[])
  14. {
  15. // Number of process
  16. int N = 2;
  17. // Assign sigHandlers
  18. signal(SIGUSR1, sigHandler);
  19. signal(SIGUSR2, sigHandler2);
  20. // array for pids to activate in order;
  21. pid_t pid[N];
  22. int i;
  23. for (i = 0; i < N; i++)
  24. {
  25. // creation child
  26. pid[i] = fork();
  27. if (pid == 0)
  28. {
  29. // if is the last child, resume the father
  30. if (i == N - 1)
  31. {
  32. kill(getppid(), SIGUSR2);
  33. }
  34. // expect SIGUSR1
  35. pause();
  36. printf("%i completed\n", getpid());
  37. exit(0);
  38. }
  39. }
  40. // expext that all child started
  41. pause();
  42. // active the last child
  43. i--;
  44. kill(pid[i], SIGUSR1);
  45. signal(SIGUSR1, sigHandler);
  46. // active other child
  47. while (wait(NULL) != -1)
  48. {
  49. i--;
  50. kill(pid[i], SIGUSR1);
  51. signal(SIGUSR1, sigHandler);
  52. }
  53. printf("All fine\n");
  54. exit(0);
  55. }

我尝试用sleep(10)替换pause()系统,但结果是终端上出现四条“All fine”消息。
我猜想这个问题源于信号的异步特性,但我不知道如何解决它。

whitzsjs

whitzsjs1#

问题的主要部分是测试if (pid == 0)-数组地址不为空。您的意思是if (pid[i] == 0)
通过这些更改以及使代码在我的默认编译选项(非常繁琐)下编译所需的最小更改,我从程序sig79中得到了以下输出:

  1. $ sig79
  2. Received other signal
  3. Received signal
  4. 15312 completed
  5. Received signal
  6. 15311 completed
  7. All fine
  8. $

在调试问题时,我使用了这段代码,它有大量的打印内容(部分原因是我被有缺陷的测试弄糊涂了)。我使用等待循环是因为在某些情况下,您的父进程可能会有它没有创建的子进程--这些情况很模糊,但这段代码说明了这些情况。注意,子进程退出时的状态与子进程编号相对应;您可以在等待循环中报告的退出状态中看到这些数字。

  1. # include <assert.h>
  2. # include <signal.h>
  3. # include <stdio.h>
  4. # include <stdlib.h>
  5. # include <sys/wait.h>
  6. # include <unistd.h>
  7. static void write_msg(size_t len, char *msg)
  8. {
  9. int pid = getpid();
  10. for (int i = 5; i > 0; i--)
  11. {
  12. msg[i-1] = pid % 10 + '0';
  13. pid /= 10;
  14. }
  15. write(STDOUT_FILENO, msg, len);
  16. }
  17. // first sigHandler
  18. static void sigHandler1(int signum)
  19. {
  20. assert(signum == SIGUSR1);
  21. static char msg[] = "XXXXX: Received signal SIGUSR1\n";
  22. write_msg(sizeof(msg) - 1, msg);
  23. }
  24. // second sigHandler
  25. static void sigHandler2(int signum)
  26. {
  27. assert(signum == SIGUSR2);
  28. static char msg[] = "XXXXX: Received signal SIGUSR2\n";
  29. write_msg(sizeof(msg) - 1, msg);
  30. }
  31. int main(void)
  32. {
  33. // Number of process
  34. int N = 2;
  35. // Assign sigHandlers
  36. signal(SIGUSR1, sigHandler1);
  37. signal(SIGUSR2, sigHandler2);
  38. printf("%d: parent at work\n", getpid());
  39. // array for pids to activate in order;
  40. pid_t pid[N];
  41. for (int i = 0; i < N; i++)
  42. {
  43. // creation child
  44. pid[i] = fork();
  45. if (pid[i] == 0)
  46. {
  47. printf("%d: child %d at play\n", getpid(), i+1);
  48. // if is the last child, resume the father
  49. if (i == N - 1)
  50. {
  51. kill(getppid(), SIGUSR2);
  52. printf("%d: signal SIGUSR2 sent to PID %d\n", getpid(), getppid());
  53. }
  54. // expect SIGUSR1
  55. pause();
  56. printf("%d: child %d completed\n", getpid(), i+1);
  57. exit(i+1);
  58. }
  59. printf("%d: child %d has PID %d\n", getpid(), i+1, pid[i]);
  60. fflush(stdout);
  61. }
  62. // expect that all children started
  63. pause();
  64. for (int i = N; i > 0; i--)
  65. {
  66. kill(pid[i - 1], SIGUSR1);
  67. printf("%d: signal SIGUSR1 sent to child %d PID %d\n", getpid(), i, pid[i - 1]);
  68. int corpse;
  69. int status;
  70. while ((corpse = wait(&status)) > 0)
  71. {
  72. if (corpse == pid[i - 1])
  73. {
  74. printf("%d: child %d PID %d exited with status 0x%.4X\n",
  75. getpid(), i, corpse, status);
  76. break;
  77. }
  78. else
  79. printf("%d: unexpected child PID %d exited with status 0x%.4X\n",
  80. getpid(), corpse, status);
  81. }
  82. }
  83. printf("%d: All fine\n", getpid());
  84. return(0);
  85. }

有一次,当我运行程序(sig59)时,我得到了输出:

  1. $ sig59
  2. 15177: parent at work
  3. 15177: child 1 has PID 15178
  4. 15178: child 1 at play
  5. 15177: child 2 has PID 15179
  6. 15179: child 2 at play
  7. 15179: signal SIGUSR2 sent to PID 15177
  8. 15177: Received signal SIGUSR2
  9. 15177: signal SIGUSR1 sent to child 2 PID 15179
  10. 15179: Received signal SIGUSR1
  11. 15179: child 2 completed
  12. 15177: child 2 PID 15179 exited with status 0x0200
  13. 15177: signal SIGUSR1 sent to child 1 PID 15178
  14. 15178: Received signal SIGUSR1
  15. 15178: child 1 completed
  16. 15177: child 1 PID 15178 exited with status 0x0100
  17. 15177: All fine
  18. $

并且,为了证明模糊情况可能发生:

  1. $ forker -s 0 -c 'exit 37' -- ./sig59
  2. forker: Setting number of child processes to 3
  3. 15138: forker at work
  4. 15138: launched 15139
  5. 15138: launched 15140
  6. 15138: launched 15141
  7. 15138: executing ./sig59
  8. 15138: parent at work
  9. 15138: child 1 has PID 15142
  10. 15138: child 2 has PID 15143
  11. 15142: child 1 at play
  12. 15143: child 2 at play
  13. 15143: signal SIGUSR2 sent to PID 15138
  14. 15138: Received signal SIGUSR2
  15. 15138: signal SIGUSR1 sent to child 2 PID 15143
  16. 15143: Received signal SIGUSR1
  17. 15143: child 2 completed
  18. 15138: child 2 PID 15143 exited with status 0x0200
  19. 15138: signal SIGUSR1 sent to child 1 PID 15142
  20. 15138: unexpected child PID 15139 exited with status 0x2500
  21. 15142: Received signal SIGUSR1
  22. 15142: child 1 completed
  23. 15138: unexpected child PID 15140 exited with status 0x2500
  24. 15138: unexpected child PID 15141 exited with status 0x2500
  25. 15138: child 1 PID 15142 exited with status 0x0100
  26. 15138: All fine
  27. $

forker程序运行三个进程,每个进程依次运行exit 37(十六进制0x 25),然后执行sig59进程(它不知道它以前的子进程是forker进程)。

展开查看全部

相关问题