面试题答案
一键面试避免竞争条件的方法
在C语言中,为了避免在处理SIGTERM信号时与其他线程的操作产生竞争条件,可以使用互斥锁(mutex)来保护共享资源。以下是具体步骤:
- 初始化互斥锁:在程序开始时,使用
pthread_mutex_init
函数初始化互斥锁。 - 加锁与解锁:在访问共享资源前,使用
pthread_mutex_lock
函数获取互斥锁,访问完成后,使用pthread_mutex_unlock
函数释放互斥锁。 - 信号处理函数中使用互斥锁:在处理SIGTERM信号的函数中,同样在访问共享资源前获取互斥锁,完成操作后释放互斥锁。
代码示例
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
// 共享资源
int shared_variable = 0;
// 互斥锁
pthread_mutex_t mutex;
// SIGTERM信号处理函数
void sigterm_handler(int signum) {
// 获取互斥锁
pthread_mutex_lock(&mutex);
printf("Received SIGTERM. Shutting down gracefully...\n");
// 执行优雅关闭操作,如关闭文件、释放资源等
// 这里以修改共享变量为例
shared_variable = -1;
// 释放互斥锁
pthread_mutex_unlock(&mutex);
}
// 线程函数
void* thread_function(void* arg) {
while (1) {
// 获取互斥锁
pthread_mutex_lock(&mutex);
shared_variable++;
printf("Thread incremented shared_variable: %d\n", shared_variable);
// 释放互斥锁
pthread_mutex_unlock(&mutex);
sleep(1);
}
return NULL;
}
int main() {
// 初始化互斥锁
if (pthread_mutex_init(&mutex, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
// 设置SIGTERM信号处理函数
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;
}
pthread_t thread;
// 创建线程
if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
printf("\n ERROR creating thread\n");
return 1;
}
// 等待线程结束
if (pthread_join(thread, NULL) != 0) {
printf("\n ERROR joining thread\n");
return 2;
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
信号处理函数中使用同步机制的注意事项
- 异步信号安全:信号处理函数应尽量保持简单,避免调用非异步信号安全的函数。在获取和释放互斥锁时,
pthread_mutex_lock
和pthread_mutex_unlock
函数通常是异步信号安全的,但要确保使用的函数库支持。 - 死锁风险:要注意避免死锁。例如,如果在信号处理函数中获取互斥锁,而主线程或其他线程在持有该互斥锁时被信号中断,就可能导致死锁。应确保信号处理函数中获取互斥锁的逻辑不会与其他线程的锁获取逻辑产生冲突。
- 信号掩码:在信号处理函数中,可能需要暂时阻塞其他信号,以避免信号嵌套导致的复杂情况。可以使用
sigprocmask
函数来设置信号掩码。