面试题答案
一键面试可能出现竞态条件的场景
- 信号处理函数与主线程共享资源:例如,主线程和信号处理函数都访问并修改同一个全局变量
is_shutdown
,用于标识程序是否要关闭。主线程可能在检查is_shutdown
后,还未来得及进行关闭操作时,信号处理函数修改了is_shutdown
,导致主线程的逻辑被打乱。 - 信号处理函数中断临界区:如果主线程正在执行一段不能被中断的代码(临界区),例如正在进行文件操作的中间阶段,此时信号处理函数被触发,可能导致文件操作不完整,数据损坏。
解决方案
- 使用互斥锁(Mutex):通过互斥锁来保护共享资源,确保同一时间只有一个线程可以访问和修改共享资源。
以下是C语言代码示例:
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pthread_mutex_t mutex;
int is_shutdown = 0;
// 信号处理函数
void sigterm_handler(int signum) {
pthread_mutex_lock(&mutex);
is_shutdown = 1;
pthread_mutex_unlock(&mutex);
}
// 线程函数
void* thread_function(void* arg) {
while (1) {
pthread_mutex_lock(&mutex);
if (is_shutdown) {
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
// 线程执行的其他任务
printf("Thread is running...\n");
sleep(1);
}
printf("Thread is shutting down...\n");
return NULL;
}
int main() {
pthread_t thread;
struct sigaction sa;
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
// 设置信号处理
sa.sa_handler = sigterm_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGTERM, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}
// 创建线程
if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
perror("pthread_create");
return 1;
}
// 主线程等待线程结束
if (pthread_join(thread, NULL) != 0) {
perror("pthread_join");
return 1;
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
- 使用原子操作:对于简单的共享变量(如
int
类型),可以使用原子操作来避免竞态条件。在C11标准中引入了<stdatomic.h>
头文件提供原子类型和操作。
以下是代码示例:
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdatomic.h>
atomic_int is_shutdown = ATOMIC_VAR_INIT(0);
// 信号处理函数
void sigterm_handler(int signum) {
atomic_store(&is_shutdown, 1);
}
// 线程函数
void* thread_function(void* arg) {
while (1) {
if (atomic_load(&is_shutdown)) {
break;
}
// 线程执行的其他任务
printf("Thread is running...\n");
sleep(1);
}
printf("Thread is shutting down...\n");
return NULL;
}
int main() {
pthread_t thread;
struct sigaction sa;
// 设置信号处理
sa.sa_handler = sigterm_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGTERM, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}
// 创建线程
if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
perror("pthread_create");
return 1;
}
// 主线程等待线程结束
if (pthread_join(thread, NULL) != 0) {
perror("pthread_join");
return 1;
}
return 0;
}