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

C语言主进程主动等待子进程就绪的优化方案咨询

高效进程同步方案替代主动轮询等待

我编写了一段C语言代码,通过fork创建子进程,主进程需等待子进程完成初始化就绪后再执行后续逻辑。目前采用while (check_activation_flag() == 1)的主动等待方式实现,但该方式效率低下,希望替换此实现。以下是主进程、子进程代码及相关共享内存操作函数,寻求高效的进程同步方案:

主进程代码

ChildPID = fork();
if (ChildPID == 0) {
    execl("./child", "./child", NULL);
    exit(0);
} else if (ChildPID < -1) {
    kill(getpid(), SIGINT);
    exit(EXIT_FAILURE);
}

atomSharedPidWriteSingle(sharedPID, getpid(), ChildPID);

while (check_activation_flag() == 1) sleep(1);

while (1) {
    sleep(1);
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
        if (WIFEXITED(status)) {
            printf("Figlio con PID %d terminato con stato %d\n", pid, WEXITSTATUS(status));
        } else {
            printf("Figlio con PID %d terminato in modo anomalo\n", pid);
        }
    }
    print_statistics();
    update_energy_consumed(energy_demand);
    setEnAvailable(-energy_demand);
    energy_available = getEnAValabe();
     printf("Total energy available: %d\n", energy_available); 
    if (energy_available < 0) kill(getpid(), SIGUSR2);
}

子进程代码

int main(){
    signal(SIGTERM, handle_sigterm);
    int sharedPID = SharedPidInit("/my_shm");
    shared_pid_data* a = (shared_pid_data*) malloc(sizeof(shared_pid_data));
    init_ipc();
    update_activation_flag();
    while(1){
        sleep(STEP_ATTIVATORE);
        a = SharedPidRead(sharedPID);
        if(a == NULL){
            printf("Memoria condivisa fallita ");
            exit(EXIT_FAILURE);
        }
        
        
        srand((unsigned int)(time(NULL) ^ getpid()));
        int pos = rand() % a->dimensione; 
        
        kill(a->atomi_pid[pos], SIGUSR1);
    }
    close(sharedPIDATOMO);
    aSharedPidDelete("/my_shm");
    return EXIT_SUCCESS;
}

相关操作函数

void atomSharedPidWriteSingle(int shm_fd, pid_t master,pid_t alimentatore,pid_t attivatore) {
    // Mappare la memoria condivisa nello spazio degli indirizzi del processo
    lock();
    shared_pid_atom = mmap(0, sizeof(shared_pid_data), PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_pid_atom == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }
    shared_pid_atom->alimentatore = alimentatore;
    shared_pid_atom->attivatore = attivatore;
    shared_pid_atom->master = master;
    
    unlock();
}

void update_activation_flag() {
    lock();
    shared_data->activation_flag += 1;
    unlock();
}

int check_activation_flag() {
    int flag;
    flag = shared_data->activation_flag;
    return (flag>=shared_data->num_ChildProcesses?0:1);
}

高效同步方案推荐

方案1:基于自定义信号的同步

利用进程间信号通知,主进程休眠等待子进程的就绪信号,完全避免轮询开销。

修改主进程

  1. 注册信号处理函数,设置就绪标志:
#include <signal.h>

volatile sig_atomic_t child_ready = 0;

void sig_child_ready(int sig) {
    child_ready = 1;
}

// 在fork操作前注册信号
signal(SIGUSR1, sig_child_ready);
  1. 替换原有轮询循环为信号等待逻辑:
// 替换 while (check_activation_flag() == 1) sleep(1);
while (!child_ready) {
    sigset_t mask;
    sigemptyset(&mask);
    sigsuspend(&mask); // 进程休眠直到收到信号,无额外CPU消耗
}

修改子进程

在update_activation_flag()完成后,向主进程发送就绪信号:

// 在update_activation_flag()之后添加
shared_pid_data* pid_data = SharedPidRead(sharedPID);
if (pid_data != NULL) {
    kill(pid_data->master, SIGUSR1);
}

方案2:基于共享内存+POSIX条件变量

适合多子进程场景,可精准等待所有子进程就绪后唤醒主进程,同步逻辑更严谨。

1. 扩展共享内存结构体

添加进程共享的互斥锁和条件变量:

#include <pthread.h>

typedef struct {
    // 原有字段
    int activation_flag;
    int num_ChildProcesses;
    // 新增同步字段
    pthread_mutex_t sync_mutex;
    pthread_cond_t sync_cond;
} shared_data_t;

2. 初始化同步对象

在共享内存初始化时,设置进程共享属性:

// 初始化互斥锁
pthread_mutexattr_t mutex_attr;
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&shared_data->sync_mutex, &mutex_attr);

// 初始化条件变量
pthread_condattr_t cond_attr;
pthread_condattr_init(&cond_attr);
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
pthread_cond_init(&shared_data->sync_cond, &cond_attr);

3. 修改主进程等待逻辑

// 替换原有轮询循环
pthread_mutex_lock(&shared_data->sync_mutex);
while (check_activation_flag() == 1) {
    // 等待条件满足,自动释放锁,被唤醒后重新获取锁
    pthread_cond_wait(&shared_data->sync_cond, &shared_data->sync_mutex);
}
pthread_mutex_unlock(&shared_data->sync_mutex);

4. 修改子进程就绪通知逻辑

更新update_activation_flag(),在所有子进程就绪时唤醒主进程:

void update_activation_flag() {
    pthread_mutex_lock(&shared_data->sync_mutex);
    shared_data->activation_flag += 1;
    // 检查是否所有子进程已就绪
    if (shared_data->activation_flag >= shared_data->num_ChildProcesses) {
        pthread_cond_signal(&shared_data->sync_cond);
    }
    pthread_mutex_unlock(&shared_data->sync_mutex);
}

方案3:基于管道的同步

利用匿名管道的阻塞读特性,主进程等待子进程写入就绪标记,实现无轮询同步。

修改主进程

  1. 创建匿名管道,fork后关闭无用端:
int pipe_fd[2];
if (pipe(pipe_fd) == -1) {
    perror("pipe");
    exit(EXIT_FAILURE);
}

ChildPID = fork();
if (ChildPID == 0) {
    close(pipe_fd[0]); // 子进程关闭读端
    execl("./child", "./child", NULL);
    exit(0);
} else if (ChildPID < -1) {
    kill(getpid(), SIGINT);
    exit(EXIT_FAILURE);
}

close(pipe_fd[1]); // 主进程关闭写端
  1. 替换轮询循环为管道读操作:
// 等待子进程写入就绪标记
char ready_flag;
read(pipe_fd[0], &ready_flag, 1);
close(pipe_fd[0]);

修改子进程

在初始化完成后,向管道写入标记(需通过共享内存传递管道写端FD):

// 扩展shared_pid_data结构体,添加pipe_write_fd字段
// 在update_activation_flag()之后添加
shared_pid_data* pid_data = SharedPidRead(sharedPID);
if (pid_data != NULL) {
    write(pid_data->pipe_write_fd, "1", 1);
    close(pid_data->pipe_write_fd);
}

内容的提问来源于stack exchange,提问作者MiusiZ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:48:12