面试题答案
一键面试竞争条件场景举例
假设主线程正在处理一个信号,该信号用于通知程序进行某些资源的清理工作。同时,一个子线程正在尝试访问并修改与该清理操作相关的资源。例如,主线程接收到SIGTERM信号,准备清理一个共享的文件描述符列表,而此时子线程正准备向该列表中添加新的文件描述符。这就可能导致数据不一致,因为主线程可能在子线程添加操作完成之前就开始清理,从而造成数据丢失或错误的清理操作。
解决方案
- 使用互斥锁(Mutex):通过互斥锁来保护共享资源,确保同一时间只有一个线程能够访问和修改这些资源。当一个线程获取到互斥锁后,其他线程必须等待该锁被释放才能访问共享资源。
- 信号掩码(Signal Masking):在子线程中屏蔽掉可能引发竞争条件的信号,只在主线程中处理这些信号。这样可以避免子线程在处理共享资源时被信号打断。
代码示例(使用互斥锁方案)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
pthread_mutex_t mutex;
int shared_resource = 0;
void* thread_function(void* arg) {
// 尝试获取互斥锁
pthread_mutex_lock(&mutex);
shared_resource++;
printf("子线程修改共享资源: %d\n", shared_resource);
// 释放互斥锁
pthread_mutex_unlock(&mutex);
return NULL;
}
void signal_handler(int signum) {
// 尝试获取互斥锁
pthread_mutex_lock(&mutex);
printf("接收到信号,正在清理共享资源: %d\n", shared_resource);
// 这里进行清理操作
// 释放互斥锁
pthread_mutex_unlock(&mutex);
}
int main() {
pthread_t thread;
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
// 设置信号处理函数
signal(SIGTERM, signal_handler);
// 创建子线程
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;
}
在上述代码中,使用互斥锁 mutex
来保护共享资源 shared_resource
。子线程在修改 shared_resource
前获取互斥锁,信号处理函数在清理资源前也获取互斥锁,这样就能避免竞争条件。