Linux下无需互斥量的事件等待方案:替代Windows EVENT
Linux下替代Windows EVENT的无锁线程退出方案
在Linux环境中,若不想为独立线程引入互斥锁,以下几种轻量级方案可替代Windows的EVENT对象,实现多线程的退出通知:
1. 使用eventfd(推荐,Linux专属轻量方案)
eventfd是Linux内核提供的专门用于进程/线程间事件通知的文件描述符,无需互斥锁,操作高效且贴合需求。
核心逻辑:
- 主线程创建
eventfd对象,初始计数器设为0 - 工作线程通过
select()/pselect()等待eventfd可读,超时则继续执行任务 - 主线程向
eventfd写入任意值,触发所有等待的线程退出
代码实现:
#include <sys/eventfd.h> #include <unistd.h> #include <pthread.h> #include <stdint.h> #include <stdio.h> #include <signal.h> int shutdown_efd; void* WorkerThread(void* arg) { uint64_t buf; do { // 执行任务逻辑 printf("Worker thread executing task...\n"); // 配置超时(5秒示例) struct timespec timeout = {5, 0}; fd_set read_fds; FD_ZERO(&read_fds); FD_SET(shutdown_efd, &read_fds); // 等待事件或超时 int ret = pselect(shutdown_efd + 1, &read_fds, NULL, NULL, &timeout, NULL); if (ret > 0 && FD_ISSET(shutdown_efd, &read_fds)) { // 读取eventfd内容重置计数器,然后退出 read(shutdown_efd, &buf, sizeof(buf)); printf("Worker thread exiting on shutdown signal...\n"); return NULL; } } while (1); } void trigger_shutdown(int sig) { uint64_t val = 1; write(shutdown_efd, &val, sizeof(val)); } int main() { // 创建eventfd,初始值为0 shutdown_efd = eventfd(0, 0); if (shutdown_efd == -1) { perror("eventfd creation failed"); return 1; } // 注册信号处理(模拟系统关机触发) signal(SIGINT, trigger_shutdown); // 启动工作线程 pthread_t tid1, tid2; pthread_create(&tid1, NULL, WorkerThread, NULL); pthread_create(&tid2, NULL, WorkerThread, NULL); printf("Press Ctrl+C to initiate shutdown...\n"); pause(); // 等待线程退出 pthread_join(tid1, NULL); pthread_join(tid2, NULL); close(shutdown_efd); return 0; }
2. 使用匿名管道(POSIX标准方案)
匿名管道是POSIX标准的IPC机制,通过读写文件描述符实现事件通知,同样无需互斥锁。
核心逻辑:
- 主线程创建匿名管道,得到读、写两个文件描述符
- 工作线程在读端等待,管道为空时
read()会阻塞,配合select()实现超时等待 - 主线程向写端写入任意数据,触发所有等待的线程退出
代码实现:
#include <unistd.h> #include <pthread.h> #include <stdio.h> #include <signal.h> #include <sys/select.h> int shutdown_pipe[2]; void* WorkerThread(void* arg) { char buf; do { // 执行任务逻辑 printf("Worker thread executing task...\n"); // 配置超时(5秒示例) struct timespec timeout = {5, 0}; fd_set read_fds; FD_ZERO(&read_fds); FD_SET(shutdown_pipe[0], &read_fds); // 等待事件或超时 int ret = pselect(shutdown_pipe[0] + 1, &read_fds, NULL, NULL, &timeout, NULL); if (ret > 0 && FD_ISSET(shutdown_pipe[0], &read_fds)) { // 读取管道内容,然后退出 read(shutdown_pipe[0], &buf, 1); printf("Worker thread exiting on shutdown signal...\n"); return NULL; } } while (1); } void trigger_shutdown(int sig) { write(shutdown_pipe[1], "x", 1); } int main() { // 创建匿名管道 if (pipe(shutdown_pipe) == -1) { perror("pipe creation failed"); return 1; } // 注册信号处理(模拟系统关机触发) signal(SIGINT, trigger_shutdown); // 启动工作线程 pthread_t tid1, tid2; pthread_create(&tid1, NULL, WorkerThread, NULL); pthread_create(&tid2, NULL, WorkerThread, NULL); printf("Press Ctrl+C to initiate shutdown...\n"); pause(); // 等待线程退出 pthread_join(tid1, NULL); pthread_join(tid2, NULL); close(shutdown_pipe[0]); close(shutdown_pipe[1]); return 0; }
3. 使用自定义信号(最简方案)
通过自定义信号(如SIGUSR1)通知线程退出,无需任何同步原语,但需注意信号处理的异步安全性。
核心逻辑:
- 工作线程注册信号处理函数,设置全局退出标志
- 主线程向所有工作线程发送自定义信号
- 工作线程在循环中检查退出标志,或在超时等待时被信号中断后退出
代码实现:
#include <pthread.h> #include <signal.h> #include <stdio.h> #include <unistd.h> volatile sig_atomic_t shutdown_flag = 0; void handle_shutdown(int sig) { shutdown_flag = 1; } void* WorkerThread(void* arg) { // 为当前线程注册信号处理 struct sigaction sa; sa.sa_handler = handle_shutdown; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); do { // 执行任务逻辑 printf("Worker thread executing task...\n"); // 超时等待(5秒),被信号中断则返回-1 struct timespec timeout = {5, 0}; nanosleep(&timeout, NULL); // 检查退出标志 if (shutdown_flag) { printf("Worker thread exiting on shutdown signal...\n"); return NULL; } } while (1); } int main() { pthread_t tid1, tid2; pthread_create(&tid1, NULL, WorkerThread, NULL); pthread_create(&tid2, NULL, WorkerThread, NULL); printf("Press Ctrl+C to initiate shutdown...\n"); pause(); // 向所有工作线程发送退出信号 pthread_kill(tid1, SIGUSR1); pthread_kill(tid2, SIGUSR1); // 等待线程退出 pthread_join(tid1, NULL); pthread_join(tid2, NULL); return 0; }
注意事项:
- 信号处理函数必须仅调用异步安全的函数(如
sig_atomic_t赋值) volatile sig_atomic_t确保退出标志在多线程间的可见性
内容的提问来源于stack exchange,提问作者PazO
相关产品推荐
相关产品推荐

