C语言pthread线程模拟航母起降程序并行异常排查
问题排查与修正方案
核心问题分析
你的代码存在两个关键问题,导致线程串行且起飞逻辑不符合预期:
1. 互斥锁持有时间过长,强制线程串行
降落和起飞线程中,Sleep(1000)(模拟起降耗时)以及非共享变量的printf操作都被放在了互斥锁的保护范围内。这意味着线程在执行耗时的模拟操作时,一直持有锁,其他线程完全无法获取锁进入临界区,必然导致串行执行。
互斥锁的作用仅应保护共享变量planes_on_deck的读写操作,耗时的业务逻辑(起降模拟)应该放在锁的范围之外。
2. 起飞线程无法及时感知条件变化
由于降落线程长期持有锁,即使planes_on_deck增长到K以上,起飞线程也无法获取锁进入临界区检查条件。只有当甲板被填满到N时,降落线程触发pthread_cond_wait释放锁,起飞线程才有机会执行,这完全违背了你的设计预期。
修正后的代码
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <windows.h> #define N 15 // 航母甲板容量 #define K 9 // 降落优先级阈值:甲板飞机数小于K时,降落优先 #define S 1 pthread_mutex_t mutex; pthread_cond_t landing_cond; pthread_cond_t takeoff_cond; int planes_on_deck = 0; void* landing() { while(1) { pthread_mutex_lock(&mutex); // 甲板满时等待 while (planes_on_deck >= N) { pthread_cond_wait(&landing_cond, &mutex); } // 仅在锁内修改共享变量 planes_on_deck++; printf("landing.\n"); // 修改完成后立即广播,通知起飞线程条件变化 pthread_cond_broadcast(&takeoff_cond); pthread_mutex_unlock(&mutex); // 耗时的起降模拟放在锁外,不阻塞其他线程 Sleep(1000); // 打印当前飞机数(非共享操作,无需锁) printf("number of planes on carrier: %d\n\n", planes_on_deck); } return NULL; } void* takeoff() { while(1) { pthread_mutex_lock(&mutex); // 甲板飞机数小于K时等待,保证降落优先 while (planes_on_deck < K) { pthread_cond_wait(&takeoff_cond, &mutex); } // 仅在锁内修改共享变量 planes_on_deck--; printf("takeoff.\n"); // 修改完成后立即广播,通知降落线程条件变化 pthread_cond_broadcast(&landing_cond); pthread_mutex_unlock(&mutex); // 耗时的起飞模拟放在锁外 Sleep(1000); printf("number of planes on carrier: %d\n\n", planes_on_deck); } return NULL; } int main() { printf("number of planes on carrier: %d\n", planes_on_deck); pthread_t landing_threads[S]; pthread_t takeoff_threads[S]; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&landing_cond, NULL); pthread_cond_init(&takeoff_cond, NULL); for (int i = 0; i < S; i++){ if (pthread_create(&landing_threads[i], NULL, landing, NULL) != 0){ perror("fail to create landing thread"); } if (pthread_create(&takeoff_threads[i], NULL, takeoff, NULL) != 0){ perror("fail to create takeoff thread"); } } for (int i = 0; i < S; i++){ if (pthread_join(takeoff_threads[i], NULL) != 0){ return 2; } if (pthread_join(landing_threads[i], NULL) != 0){ return 2; } } pthread_mutex_destroy(&mutex); pthread_cond_destroy(&landing_cond); pthread_cond_destroy(&takeoff_cond); return 0; }
关键修改说明
- 缩小锁的作用范围:仅在修改和检查共享变量
planes_on_deck时持有锁,将Sleep和非共享的打印操作移到锁外,让多个线程可以并行执行耗时的模拟逻辑。 - 调整广播时机:在修改完
planes_on_deck后、解锁前调用pthread_cond_broadcast,确保其他等待的线程能及时感知条件变化,避免解锁后广播可能导致的延迟。 - 明确优先级逻辑:起飞线程在
planes_on_deck < K时持续等待,保证当甲板飞机数不足K时,降落线程可以优先执行,符合设计预期。
内容的提问来源于stack exchange,提问作者wojtek c
相关产品推荐
相关产品推荐

