main.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include <errno.h>
  2. #include <poll.h>
  3. #include <pthread.h>
  4. #include <signal.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/time.h>
  9. #include <unistd.h>
  10. int pipe_fd[2]; // 管道文件描述符数组
  11. int child_can_exit = 0; // 子进程是否可以退出的标志
  12. int signal_pid = 0;
  13. int poll_errno; // poll错误码
  14. #define WRITE_WAIT_SEC 3
  15. #define POLL_TIMEOUT_SEC 5
  16. #define EXPECTED_MESSAGE "Data is ready!\n"
  17. #define POLL_DELTA_MS 1000
  18. #define min(a, b) ((a) < (b) ? (a) : (b))
  19. // 信号处理函数
  20. void signal_handler(int signo) {
  21. printf("[PID: %d, TID: %lu] Signal %d received.\n", getpid(), pthread_self(),
  22. signo);
  23. }
  24. // 线程函数,用于在n秒后向管道写入数据
  25. void *writer_thread(void *arg) {
  26. int seconds = WRITE_WAIT_SEC;
  27. for (int i = 0; i < seconds; i++) {
  28. printf("[PID: %d, TID: %lu] Waiting for %d seconds...\n", getpid(),
  29. pthread_self(), seconds - i);
  30. sleep(1);
  31. kill(signal_pid, SIGUSR1); // 发送信号
  32. }
  33. const char *message = EXPECTED_MESSAGE;
  34. write(pipe_fd[1], message, strlen(message)); // 写入管道
  35. printf("[PID: %d, TID: %lu] Data written to pipe.\n", getpid(),
  36. pthread_self());
  37. close(pipe_fd[1]); // 关闭写端
  38. printf("[PID: %d, TID: %lu] Pipe write end closed.\n", getpid(),
  39. pthread_self());
  40. while (child_can_exit == 0) {
  41. printf("[PID: %d, TID: %lu] Waiting for main to finish...\n", getpid(),
  42. pthread_self());
  43. sleep(1);
  44. }
  45. return NULL;
  46. }
  47. int main() {
  48. pthread_t tid;
  49. struct pollfd fds[1];
  50. int ret;
  51. int test_passed = 1; // 假设测试通过
  52. // 创建管道
  53. if (pipe(pipe_fd) == -1) {
  54. perror("pipe");
  55. exit(EXIT_FAILURE);
  56. }
  57. // 设置信号处理函数
  58. struct sigaction sa;
  59. sa.sa_handler = signal_handler;
  60. sigemptyset(&sa.sa_mask);
  61. sa.sa_flags = SA_RESTART;
  62. if (sigaction(SIGUSR1, &sa, NULL) == -1) {
  63. perror("sigaction");
  64. exit(EXIT_FAILURE);
  65. }
  66. signal_pid = getpid(); // 设置信号接收进程ID
  67. // 创建写线程
  68. if (pthread_create(&tid, NULL, writer_thread, NULL) != 0) {
  69. perror("pthread_create");
  70. exit(EXIT_FAILURE);
  71. }
  72. // 设置poll监视的文件描述符
  73. fds[0].fd = pipe_fd[0]; // 监视管道的读端
  74. fds[0].events = POLLIN; // 监视是否有数据可读
  75. printf("[PID: %d, TID: %lu] Waiting for data...\n", getpid(), pthread_self());
  76. // 在 poll 调用前后添加时间统计
  77. struct timeval start_time, end_time;
  78. gettimeofday(&start_time, NULL); // 记录 poll 开始时间
  79. ret = poll(fds, 1, POLL_TIMEOUT_SEC * 1000); // 调用 poll
  80. poll_errno = errno;
  81. gettimeofday(&end_time, NULL); // 记录 poll 结束时间
  82. // 计算 poll 的总耗时(单位:毫秒)
  83. long poll_duration_ms = (end_time.tv_sec - start_time.tv_sec) * 1000 +
  84. (end_time.tv_usec - start_time.tv_usec) / 1000;
  85. if (abs((int)poll_duration_ms -
  86. min(POLL_TIMEOUT_SEC, WRITE_WAIT_SEC) * 1000) >= POLL_DELTA_MS) {
  87. printf("Poll duration: %ld ms, expected: %d ms, errno: %s\n",
  88. poll_duration_ms, POLL_TIMEOUT_SEC * 1000, strerror(poll_errno));
  89. test_passed = 0; // 测试失败(如果 poll 耗时与预期相差较大,认为测试未通过)
  90. }
  91. if (test_passed == 0) {
  92. } else if (ret == -1) {
  93. printf("poll errno: %s\n", strerror(poll_errno));
  94. test_passed = 0; // 测试失败
  95. } else if (ret == 0) {
  96. printf("Timeout! No data available.\n");
  97. test_passed = 0; // 测试失败
  98. } else {
  99. if (fds[0].revents & POLLIN) {
  100. char buffer[1024];
  101. ssize_t count = read(pipe_fd[0], buffer, sizeof(buffer)); // 读取数据
  102. if (count > 0) {
  103. printf("Data received: %s", buffer);
  104. // 检查读取的数据是否与预期一致
  105. if (strcmp(buffer, EXPECTED_MESSAGE) != 0) {
  106. printf("Unexpected data received.\n");
  107. test_passed = 0; // 测试失败
  108. }
  109. } else {
  110. printf("No data read from pipe.\n");
  111. test_passed = 0; // 测试失败
  112. }
  113. } else {
  114. printf("Unexpected event on pipe.\n");
  115. test_passed = 0; // 测试失败
  116. }
  117. }
  118. child_can_exit = 1; // 允许子进程退出
  119. // 等待写线程结束
  120. pthread_join(tid, NULL);
  121. close(pipe_fd[0]); // 关闭读端
  122. if (test_passed) {
  123. printf("Test passed!\n");
  124. } else {
  125. printf("Test failed!\n");
  126. }
  127. printf("Program finished.\n");
  128. return test_passed ? 0 : 1; // 返回0表示测试通过,返回1表示测试失败
  129. }