C语言使用fork和共享内存实现F1训练模拟时程序无法停止问题求助
问题根因
- 子进程执行完模拟逻辑后未调用
exit()退出,会重新进入fork循环创建更多子进程,形成进程嵌套无限生成的问题,导致程序永远不会终止 - 父进程fork逻辑错误:每创建1个子进程就立刻
wait(NULL)阻塞等待子进程跑完,导致20辆车是串行模拟而非并行,同时父进程的渲染逻辑和子进程创建强绑定,完全不符合设计预期 - 缺少退出触发条件:既没有判断所有子进程是否已达到耗时上限,也没有实现指定展示次数后退出的逻辑
- 随机数种子
srand(time(NULL) + getpid())放在循环内,同一秒内生成的随机数完全重复,模拟结果失真
修复后完整代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #include <stdbool.h> #include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #include <sys/wait.h> #define NUMBER_OF_CARS 20 #define MIN 25000 // time generator #define MAX 40000 #define DISPLAY_COUNT 10 // 自定义展示次数,达到后自动退出 int numeroVoiture[NUMBER_OF_CARS] = {44, 77, 11, 33, 3, 4, 5, 18, 14, 31, 16, 55, 10, 22, 7, 99, 9, 47, 6, 63}; pid_t car_pids[NUMBER_OF_CARS]; // 存储所有子进程pid,用于后续终止 typedef struct { unsigned int id; unsigned int s1; unsigned int s2; unsigned int s3; unsigned int best_S1; unsigned int best_S2; unsigned int best_S3; unsigned int tempsTotal; unsigned int best_Circuit; unsigned int lap; unsigned int compteurStand; unsigned int out; } voiture; voiture *shared_memory; voiture copyTableau[NUMBER_OF_CARS]; volatile sig_atomic_t global_exit = 0; // 全局退出标记 int faireDesTours(int i); unsigned int generateNumber(void); void afficherTableau(void); int compare (const void * a, const void * b); void initVoiture(int i); void sortLap(void); int main(void) { /*************************************************** * Creating shared memory * ****************************************************/ int segment_id = shmget(IPC_PRIVATE, sizeof(voiture) * NUMBER_OF_CARS, 0666 | IPC_CREAT); if (segment_id == -1) { perror("shmget() failed !"); exit(EXIT_FAILURE); } shared_memory = shmat(segment_id, NULL, 0); if (shared_memory == (void *) (-1)) { perror("shmat() failed !"); exit(EXIT_FAILURE); } /********************************************************** * Creation of child / cars * **********************************************************/ for (int i = 0; i < NUMBER_OF_CARS; ++i) { pid_t pid = fork(); if (pid == -1) { perror("fork failed !"); exit(EXIT_FAILURE); } /******** child *********/ if(pid == 0) { shared_memory[i].id = numeroVoiture[i]; srand(time(NULL) + getpid()); // 随机数种子只初始化一次 faireDesTours(i); exit(EXIT_SUCCESS); // 子进程模拟完直接退出,避免回到fork循环 } /******** father *********/ else { car_pids[i] = pid; // 记录子进程pid } } // 父进程独立渲染逻辑 int display_counter = 0; while (display_counter < DISPLAY_COUNT) { system("clear"); memcpy( copyTableau, shared_memory, sizeof(copyTableau) ); qsort( copyTableau, NUMBER_OF_CARS, sizeof(voiture), compare ); sortLap(); afficherTableau(); display_counter++; sleep(1); } // 达到展示次数后终止所有子进程 global_exit = 1; for (int i = 0; i < NUMBER_OF_CARS; i++) { kill(car_pids[i], SIGTERM); waitpid(car_pids[i], NULL, 0); } /******** Detach memory segments *********/ shmdt(shared_memory); /******** Delete shared memory *********/ shmctl(segment_id, IPC_RMID, NULL); exit(EXIT_SUCCESS); } unsigned int tempsMaxCircuit = 5400000; int faireDesTours( int i ) { initVoiture(i); unsigned int tour_complet; while (!global_exit && shared_memory[i].tempsTotal <= tempsMaxCircuit) { tour_complet = 0; /* **** S1 **** */ shared_memory[i].s1 = generateNumber(); if (shared_memory[i].s1 < shared_memory[i].best_S1) { shared_memory[i].best_S1 = shared_memory[i].s1; } shared_memory[i].tempsTotal += shared_memory[i].s1; tour_complet += shared_memory[i].s1; if (global_exit || shared_memory[i].tempsTotal >= tempsMaxCircuit) break; /* **** S2 **** */ shared_memory[i].s2 = generateNumber(); if (shared_memory[i].s2 < shared_memory[i].best_S2) { shared_memory[i].best_S2 = shared_memory[i].s2; } shared_memory[i].tempsTotal += shared_memory[i].s2; tour_complet += shared_memory[i].s2; if (global_exit || shared_memory[i].tempsTotal >= tempsMaxCircuit) break; /* **** S3 **** */ shared_memory[i].s3 = generateNumber(); if (shared_memory[i].s3 < shared_memory[i].best_S3) { shared_memory[i].best_S3 = shared_memory[i].s3; } shared_memory[i].tempsTotal += shared_memory[i].s3; tour_complet += shared_memory[i].s3; if (global_exit || shared_memory[i].tempsTotal >= tempsMaxCircuit) break; /* **** Best Time Circuit **** */ if (tour_complet < shared_memory[i].best_Circuit) { shared_memory[i].best_Circuit = tour_complet; } } return 0; } unsigned int generateNumber(void) { return rand()%(MAX-MIN+1)+MIN; } void afficherTableau(void) { // Display printf("\n\tBest times per complete lap\n"); printf(" ===================================================================================\n"); printf(" | ID | s1 | s2 | s3 | Tour | LAP |\n"); printf(" |==================================================================================\n"); for (int i = 0; i < NUMBER_OF_CARS; i++){ printf(" | %2d | %5d | %5d | %5d | %6d | %5d |\n", \ copyTableau[i].id, \ copyTableau[i].s1, copyTableau[i].s2, copyTableau[i].s3, \ copyTableau[i].best_Circuit,\ copyTableau[i].lap); } printf(" ===================================================================================\n\n"); } // function sort int compare(const void * a, const void * b) { voiture *voitureA = (voiture *)a; voiture *voitureB = (voiture *)b; return ( voitureA->best_Circuit - voitureB->best_Circuit ); } // init each structure value of car void initVoiture(int i) { shared_memory[i].s1 = 0; shared_memory[i].s2 = 0; shared_memory[i].s3 = 0; shared_memory[i].best_S1 = MAX; shared_memory[i].best_S2 = MAX; shared_memory[i].best_S3 = MAX; shared_memory[i].best_Circuit = 3 * MAX; shared_memory[i].tempsTotal = 0; shared_memory[i].lap = 0; shared_memory[i].compteurStand = 0; shared_memory[i].out = false; } void sortLap(void) { unsigned int difference; for (int i = 1; i < NUMBER_OF_CARS; i++) { difference = ( copyTableau[i].best_Circuit - copyTableau[i - 1].best_Circuit ); copyTableau[i].lap = difference; } }
修改说明
- 新增
DISPLAY_COUNT宏定义,可自行调整需要展示的次数,达到次数后程序自动退出 - 修复子进程未退出的问题,子进程模拟结束后直接调用
exit(),避免无限创建子进程 - 调整父子进程逻辑:父进程先一次性创建所有车辆对应的子进程,再独立执行每秒刷新的渲染逻辑,实现多车并行模拟
- 随机数种子移到子进程循环外,仅初始化一次,保证随机数生成正常
- 新增全局退出标记,父进程触发退出后子进程会立刻终止模拟,避免资源残留
内容的提问来源于stack exchange,提问作者bendour
相关产品推荐
相关产品推荐

