123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- #include <errno.h>
- #include <poll.h>
- #include <pthread.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/time.h>
- #include <unistd.h>
- int pipe_fd[2]; // 管道文件描述符数组
- int child_can_exit = 0; // 子进程是否可以退出的标志
- int signal_pid = 0;
- int poll_errno; // poll错误码
- #define WRITE_WAIT_SEC 3
- #define POLL_TIMEOUT_SEC 5
- #define EXPECTED_MESSAGE "Data is ready!\n"
- #define POLL_DELTA_MS 1000
- #define min(a, b) ((a) < (b) ? (a) : (b))
- // 信号处理函数
- void signal_handler(int signo) {
- printf("[PID: %d, TID: %lu] Signal %d received.\n", getpid(), pthread_self(),
- signo);
- }
- // 线程函数,用于在n秒后向管道写入数据
- void *writer_thread(void *arg) {
- int seconds = WRITE_WAIT_SEC;
- for (int i = 0; i < seconds; i++) {
- printf("[PID: %d, TID: %lu] Waiting for %d seconds...\n", getpid(),
- pthread_self(), seconds - i);
- sleep(1);
- kill(signal_pid, SIGUSR1); // 发送信号
- }
- const char *message = EXPECTED_MESSAGE;
- write(pipe_fd[1], message, strlen(message)); // 写入管道
- printf("[PID: %d, TID: %lu] Data written to pipe.\n", getpid(),
- pthread_self());
- close(pipe_fd[1]); // 关闭写端
- printf("[PID: %d, TID: %lu] Pipe write end closed.\n", getpid(),
- pthread_self());
- while (child_can_exit == 0) {
- printf("[PID: %d, TID: %lu] Waiting for main to finish...\n", getpid(),
- pthread_self());
- sleep(1);
- }
- return NULL;
- }
- int main() {
- pthread_t tid;
- struct pollfd fds[1];
- int ret;
- int test_passed = 1; // 假设测试通过
- // 创建管道
- if (pipe(pipe_fd) == -1) {
- perror("pipe");
- exit(EXIT_FAILURE);
- }
- // 设置信号处理函数
- struct sigaction sa;
- sa.sa_handler = signal_handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- if (sigaction(SIGUSR1, &sa, NULL) == -1) {
- perror("sigaction");
- exit(EXIT_FAILURE);
- }
- signal_pid = getpid(); // 设置信号接收进程ID
- // 创建写线程
- if (pthread_create(&tid, NULL, writer_thread, NULL) != 0) {
- perror("pthread_create");
- exit(EXIT_FAILURE);
- }
- // 设置poll监视的文件描述符
- fds[0].fd = pipe_fd[0]; // 监视管道的读端
- fds[0].events = POLLIN; // 监视是否有数据可读
- printf("[PID: %d, TID: %lu] Waiting for data...\n", getpid(), pthread_self());
- // 在 poll 调用前后添加时间统计
- struct timeval start_time, end_time;
- gettimeofday(&start_time, NULL); // 记录 poll 开始时间
- ret = poll(fds, 1, POLL_TIMEOUT_SEC * 1000); // 调用 poll
- poll_errno = errno;
- gettimeofday(&end_time, NULL); // 记录 poll 结束时间
- // 计算 poll 的总耗时(单位:毫秒)
- long poll_duration_ms = (end_time.tv_sec - start_time.tv_sec) * 1000 +
- (end_time.tv_usec - start_time.tv_usec) / 1000;
- if (abs((int)poll_duration_ms -
- min(POLL_TIMEOUT_SEC, WRITE_WAIT_SEC) * 1000) >= POLL_DELTA_MS) {
- printf("Poll duration: %ld ms, expected: %d ms, errno: %s\n",
- poll_duration_ms, POLL_TIMEOUT_SEC * 1000, strerror(poll_errno));
- test_passed = 0; // 测试失败(如果 poll 耗时与预期相差较大,认为测试未通过)
- }
- if (test_passed == 0) {
- } else if (ret == -1) {
- printf("poll errno: %s\n", strerror(poll_errno));
- test_passed = 0; // 测试失败
- } else if (ret == 0) {
- printf("Timeout! No data available.\n");
- test_passed = 0; // 测试失败
- } else {
- if (fds[0].revents & POLLIN) {
- char buffer[1024];
- ssize_t count = read(pipe_fd[0], buffer, sizeof(buffer)); // 读取数据
- if (count > 0) {
- printf("Data received: %s", buffer);
- // 检查读取的数据是否与预期一致
- if (strcmp(buffer, EXPECTED_MESSAGE) != 0) {
- printf("Unexpected data received.\n");
- test_passed = 0; // 测试失败
- }
- } else {
- printf("No data read from pipe.\n");
- test_passed = 0; // 测试失败
- }
- } else {
- printf("Unexpected event on pipe.\n");
- test_passed = 0; // 测试失败
- }
- }
- child_can_exit = 1; // 允许子进程退出
- // 等待写线程结束
- pthread_join(tid, NULL);
- close(pipe_fd[0]); // 关闭读端
- if (test_passed) {
- printf("Test passed!\n");
- } else {
- printf("Test failed!\n");
- }
- printf("Program finished.\n");
- return test_passed ? 0 : 1; // 返回0表示测试通过,返回1表示测试失败
- }
|