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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
| #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/epoll.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <signal.h>
int main() { int epfd, sockfd, nfds; struct epoll_event ev, events[10]; sigset_t mask, orig_mask; printf("=== Epoll_pwait 函数示例 ===\n"); // 创建epoll实例 epfd = epoll_create1(EPOLL_CLOEXEC); if (epfd == -1) { perror("epoll_create1 失败"); exit(EXIT_FAILURE); } printf("创建epoll实例: %d\n", epfd); // 创建测试用的socket sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("创建socket失败"); close(epfd); exit(EXIT_FAILURE); } printf("创建测试socket: %d\n", sockfd); // 设置socket为非阻塞模式 int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); // 添加socket到epoll监视集合 ev.events = EPOLLIN | EPOLLOUT; ev.data.fd = sockfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) { perror("epoll_ctl 添加失败"); close(sockfd); close(epfd); exit(EXIT_FAILURE); } printf("添加socket到epoll监视集合\n"); // 示例1: 基本使用(不改变信号掩码) printf("\n示例1: 基本使用(不改变信号掩码)\n"); nfds = epoll_pwait(epfd, events, 10, 1000, NULL); if (nfds == -1) { if (errno == EINTR) { printf("等待被信号中断\n"); } else { perror("epoll_pwait 失败"); } } else { printf("等待完成,就绪事件数: %d\n", nfds); } // 示例2: 设置临时信号掩码 printf("\n示例2: 设置临时信号掩码\n"); // 初始化信号掩码 sigemptyset(&mask); sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR2); printf("设置临时阻塞SIGUSR1和SIGUSR2信号\n"); nfds = epoll_pwait(epfd, events, 10, 2000, &mask); if (nfds == -1) { if (errno == EINTR) { printf("等待被未阻塞的信号中断\n"); } else { perror("epoll_pwait 失败"); } } else { printf("等待完成,就绪事件数: %d\n", nfds); } // 示例3: 与普通epoll_wait对比 printf("\n示例3: 与epoll_wait对比\n"); printf("epoll_wait vs epoll_pwait的区别:\n"); printf("epoll_wait:\n"); printf(" - 使用当前进程的信号掩码\n"); printf(" - 无法在调用中临时改变信号掩码\n\n"); printf("epoll_pwait:\n"); printf(" - 可以指定临时信号掩码\n"); printf(" - 原子性地设置掩码和等待\n"); printf(" - 避免竞态条件\n\n"); // 示例4: 原子性操作演示 printf("示例4: 原子性操作演示\n"); printf("说明epoll_pwait的原子性优势:\n"); printf("传统方式(非原子性):\n"); printf(" 1. sigprocmask(SIG_BLOCK, &mask, &orig_mask);\n"); printf(" 2. epoll_wait(epfd, events, 10, -1);\n"); printf(" 3. sigprocmask(SIG_SETMASK, &orig_mask, NULL);\n"); printf(" 问题: 在步骤1和2之间可能收到信号\n\n"); printf("epoll_pwait方式(原子性):\n"); printf(" epoll_pwait(epfd, events, 10, -1, &mask);\n"); printf(" 优势: 设置掩码和等待是原子操作\n\n"); // 示例5: 错误处理演示 printf("示例5: 错误处理演示\n"); // 使用无效的信号掩码 nfds = epoll_pwait(epfd, events, 10, 1000, (sigset_t*)-1); if (nfds == -1) { if (errno == EINVAL) { printf("无效信号掩码错误处理正确: %s\n", strerror(errno)); } } // 其他错误与epoll_wait相同 nfds = epoll_pwait(-1, events, 10, 1000, &mask); if (nfds == -1) { if (errno == EBADF) { printf("无效epoll文件描述符错误处理正确\n"); } } // 示例6: 实际应用场景 printf("\n示例6: 实际应用场景\n"); printf("多线程服务器中的信号处理:\n"); printf("场景: 主线程处理网络事件,信号处理线程处理信号\n"); printf("要求: 主线程在epoll_wait期间不被某些信号中断\n\n"); printf("实现方案:\n"); printf("sigset_t mask;\n"); printf("sigemptyset(&mask);\n"); printf("sigaddset(&mask, SIGUSR1); // 阻塞用户信号\n"); printf("sigaddset(&mask, SIGALRM); // 阻塞定时器信号\n"); printf("epoll_pwait(epfd, events, MAX_EVENTS, -1, &mask);\n\n"); // 示例7: 信号掩码操作演示 printf("示例7: 信号掩码操作演示\n"); // 创建复杂的信号掩码 sigset_t complex_mask; sigemptyset(&complex_mask); // 添加多个信号到掩码 int signals[] = {SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGALRM}; const char *signal_names[] = {"SIGINT", "SIGTERM", "SIGUSR1", "SIGUSR2", "SIGALRM"}; printf("创建包含以下信号的掩码:\n"); for (int i = 0; i < 5; i++) { sigaddset(&complex_mask, signals[i]); printf(" %s\n", signal_names[i]); } printf("使用复杂信号掩码进行epoll_pwait\n"); nfds = epoll_pwait(epfd, events, 10, 1000, &complex_mask); if (nfds != -1) { printf("epoll_pwait成功完成\n"); } // 示例8: 线程安全考虑 printf("\n示例8: 线程安全考虑\n"); printf("在多线程环境中的使用:\n"); printf("1. 每个线程可以有自己的epoll实例\n"); printf("2. 每个线程可以设置不同的信号掩码\n"); printf("3. 避免线程间的信号处理冲突\n"); printf("4. 提高信号处理的精确性\n\n"); printf("线程特定的信号掩码设置:\n"); printf("线程1: 阻塞SIGUSR1, SIGUSR2\n"); printf("线程2: 阻塞SIGALRM, SIGVTALRM\n"); printf("线程3: 不阻塞任何信号\n\n"); // 示例9: 性能和安全性 printf("示例9: 性能和安全性\n"); printf("epoll_pwait的优势:\n"); printf("1. 原子性操作,避免竞态条件\n"); printf("2. 更精确的信号控制\n"); printf("3. 提高程序的可靠性\n"); printf("4. 简化信号处理逻辑\n\n"); printf("使用建议:\n"); printf("1. 在需要精确信号控制时使用epoll_pwait\n"); printf("2. 合理设计信号掩码\n"); printf("3. 注意信号处理的线程安全性\n"); printf("4. 在多线程环境中谨慎使用\n\n"); // 清理资源 epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL); close(sockfd); close(epfd); printf("总结:\n"); printf("epoll_pwait是epoll_wait的增强版本\n"); printf("支持临时信号掩码设置\n"); printf("提供原子性的信号控制\n"); printf("适用于需要精确信号处理的场景\n"); printf("在现代Linux系统中推荐使用\n"); return 0; }
|