1. 信号处理函数与多线程通信机制
- 共享变量:通过定义一个共享的全局变量,例如
volatile sig_atomic_t stop_flag
,信号处理函数在接收到SIGTERM
信号时设置这个标志,线程通过检查这个标志来决定是否退出。
- 条件变量:结合互斥锁和条件变量来实现线程间的同步。当
stop_flag
被设置时,主线程可以通过条件变量通知其他线程。
2. 关键代码片段及解释
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 定义共享变量
volatile sig_atomic_t stop_flag = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 信号处理函数
void sig_handler(int signum) {
pthread_mutex_lock(&mutex);
stop_flag = 1;
pthread_cond_broadcast(&cond); // 通知所有等待在条件变量上的线程
pthread_mutex_unlock(&mutex);
}
// 线程函数
void* thread_function(void* arg) {
pthread_mutex_lock(&mutex);
while (!stop_flag) {
// 等待条件变量,同时释放互斥锁
pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);
printf("Thread is exiting...\n");
return NULL;
}
int main() {
pthread_t tid;
// 注册信号处理函数
struct sigaction sa;
sa.sa_handler = sig_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
// 创建线程
if (pthread_create(&tid, NULL, thread_function, NULL) != 0) {
perror("pthread_create");
return 1;
}
// 主线程继续执行其他任务
while (!stop_flag) {
sleep(1);
}
// 等待线程退出
pthread_join(tid, NULL);
// 清理资源
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
- 共享变量
stop_flag
:volatile sig_atomic_t
类型保证了对该变量的访问是原子操作,并且防止编译器优化对其访问的顺序。信号处理函数可以安全地修改这个变量,线程也能安全地读取这个变量。
- 信号处理函数
sig_handler
:在接收到SIGTERM
信号时,首先获取互斥锁,设置stop_flag
,然后通过pthread_cond_broadcast
通知所有等待在条件变量cond
上的线程,最后释放互斥锁。
- 线程函数
thread_function
:线程在开始时获取互斥锁,然后通过pthread_cond_wait
等待条件变量。这个函数会自动释放互斥锁并阻塞线程,当条件变量被通知时,它会重新获取互斥锁并检查stop_flag
。如果stop_flag
为真,则退出线程。
- 主线程:在主线程中,注册信号处理函数,创建线程并等待
stop_flag
被设置。当stop_flag
被设置后,主线程调用pthread_join
等待线程退出,最后清理互斥锁和条件变量。通过这种方式,有效地避免了竞态条件,实现了信号处理函数与多线程之间的安全通信和线程同步。