多线程中,信号在哪个线程中处理是不确定的,可能被任意一个线程处理
下边的代码可以验证该结论,多次Ctrl+c,会被不同的线程捕获此信号,并处理,最终每个线程死锁,阻塞在等待锁的状态
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t lock;
// 信号处理函数
void sigint_handler(int signum) {
printf("Received SIGINT signal, %ld\n",pthread_self());
printf("lock line %d\n",__LINE__);
pthread_mutex_lock(&lock);
//usleep(100);
pthread_mutex_unlock(&lock);
printf("unlock line %d\n",__LINE__);
}
// 线程函数
void* thread_func(void* arg) {
while (1) {
printf("thread process, %ld\n",pthread_self());
usleep(100000);
}
return NULL;
}
int main() {
signal(SIGINT, sigint_handler); // 注册SIGINT信号的处理函数
printf("main process, %ld\n",pthread_self());
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread_func, NULL); // 创建一个新线程
pthread_create(&thread2, NULL, thread_func, NULL); // 创建一个新线程
while(1)
{
printf("lock line %d\n",__LINE__);
pthread_mutex_lock(&lock);
usleep(100000); //如果在这个时间段触发中断,并且有主线程处理中断任务,即调用sigint_handler,那么就会出现死锁
pthread_mutex_unlock(&lock);
printf("unlock line %d\n",__LINE__);
}
pthread_join(thread1, NULL); // 等待新线程退出
pthread_join(thread2, NULL); // 等待新线程退出
return 0;
}
结果:
main process, 139693373089600
thread process, 139693364594432
lock line 34
thread process, 139693356201728
thread process, 139693364594432
unlock line 38
lock line 34
thread process, 139693356201728
thread process, 139693364594432
unlock line 38
lock line 34
thread process, 139693356201728
^CReceived SIGINT signal, 139693373089600
lock line 10
thread process, 139693364594432
thread process, 139693356201728
thread process, 139693364594432
thread process, 139693364594432
thread process, 139693356201728
thread process, 139693364594432
thread process, 139693356201728
^CReceived SIGINT signal, 139693364594432
lock line 10
thread process, 139693356201728
thread process, 139693356201728
thread process, 139693356201728
thread process, 139693356201728
thread process, 139693356201728
thread process, 139693356201728
thread process, 139693356201728
^CReceived SIGINT signal, 139693356201728
lock line 10
^C^C^C
分析:先主线程usleep(100000);期间 触发中断sigint_handler,并且中断处理任务由主线程处理时(系统默认会把中断信号有主线程处理),因此首先会导致主线程死锁。此后再次触发中断信号时,系统会将中断信号给另一个正在工作的线程处理,此时另一个线程也会死锁。此后再次触发中断时,最后一个线程死锁。
因此在中断响应函数中使用锁时要特别注意!!!