You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:54:05