面试题答案
一键面试- 实现步骤
- 信号定义:
- 首先,在程序中定义一个全局变量来作为信号标志,例如:
这里使用volatile sig_atomic_t signal_flag = 0;
volatile sig_atomic_t
类型是为了确保对这个变量的访问是原子操作,避免编译器优化导致的意外结果。
- 首先,在程序中定义一个全局变量来作为信号标志,例如:
- 工作线程:
- 每个工作线程在其循环中需要不断检查这个信号标志。例如:
void* worker_thread(void* arg) { while (1) { // 检查信号标志 if (signal_flag) { // 执行特定任务 // 例如: printf("Worker thread is doing the specific task.\n"); // 重置信号标志,如果需要重复使用信号机制,可以在这里重置 signal_flag = 0; } // 线程的其他工作,例如处理其他任务或者睡眠 sleep(1); } return NULL; }
- 每个工作线程在其循环中需要不断检查这个信号标志。例如:
- 主线程:
- 主线程在需要发送信号时,设置信号标志。例如:
int main() { pthread_t threads[NUM_THREADS]; // 创建工作线程 for (int i = 0; i < NUM_THREADS; i++) { pthread_create(&threads[i], NULL, worker_thread, NULL); } // 主线程做其他工作 sleep(5); // 发送信号 signal_flag = 1; // 等待所有线程完成(这里只是示例,实际可能不需要等待所有线程完成特定任务后才退出) for (int i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } return 0; }
- 主线程在需要发送信号时,设置信号标志。例如:
- 信号定义:
- 线程间同步与避免竞争条件
- 互斥锁(Mutex):
- 可以使用互斥锁来保护对
signal_flag
的访问。在主线程设置信号标志和工作线程检查信号标志时,都需要先获取互斥锁。 - 定义互斥锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- 在主线程发送信号时:
pthread_mutex_lock(&mutex); signal_flag = 1; pthread_mutex_unlock(&mutex);
- 在工作线程检查信号标志时:
pthread_mutex_lock(&mutex); if (signal_flag) { // 执行特定任务 signal_flag = 0; } pthread_mutex_unlock(&mutex);
- 可以使用互斥锁来保护对
- 条件变量(Condition Variable):
- 条件变量可以更高效地实现线程间的同步。主线程在设置信号标志后,可以通知条件变量,工作线程在等待信号时,可以等待条件变量。
- 定义条件变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- 在主线程发送信号时:
pthread_mutex_lock(&mutex); signal_flag = 1; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mutex);
- 在工作线程检查信号标志时:
pthread_mutex_lock(&mutex); while (!signal_flag) { pthread_cond_wait(&cond, &mutex); } // 执行特定任务 signal_flag = 0; pthread_mutex_unlock(&mutex);
- 屏障(Barrier):
- 如果主线程需要确保所有工作线程都收到信号并开始执行特定任务后再继续执行其他操作,可以使用屏障。例如:
- 定义屏障:
pthread_barrier_t barrier; pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1);
- 在工作线程中,当收到信号并开始执行特定任务前,调用屏障:
pthread_mutex_lock(&mutex); if (signal_flag) { pthread_barrier_wait(&barrier); // 执行特定任务 signal_flag = 0; } pthread_mutex_unlock(&mutex);
- 在主线程发送信号后,也调用屏障:
pthread_mutex_lock(&mutex); signal_flag = 1; pthread_mutex_unlock(&mutex); pthread_barrier_wait(&barrier);
- 原子操作:
- 除了使用
volatile sig_atomic_t
类型确保对signal_flag
的原子访问外,也可以使用平台特定的原子操作函数。例如在C11标准中,可以使用<stdatomic.h>
头文件中的原子操作函数。例如atomic_store
和atomic_load
来设置和读取signal_flag
,这样可以更细粒度地控制原子操作,并且在多平台上有更好的兼容性。例如:#include <stdatomic.h> atomic_int signal_flag = ATOMIC_VAR_INIT(0); // 主线程设置信号 atomic_store(&signal_flag, 1); // 工作线程检查信号 if (atomic_load(&signal_flag)) { // 执行任务 atomic_store(&signal_flag, 0); }
- 除了使用
- 互斥锁(Mutex):