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

进程环中信号传递代码中途停滞的原因咨询

Why Your Process Ring Signal Passing Gets Stuck

Hey John, let's break down exactly why your code stalls after just a couple of iterations—there are some critical flaws in how you're handling PID management, process state, and synchronization:

1. The getpid()+1 Assumption is Fatal

The biggest issue is guessing the next process's PID with getpid()+1. Operating systems assign PIDs dynamically, and there's zero guarantee a child or sibling process will have a PID exactly one higher than yours. When you send a signal to a non-existent (or wrong) PID, the signal gets lost, and your ring breaks immediately.

2. Global Variables Don't Survive execl

When you use execl, you're replacing the entire process's memory space with a fresh instance of your program. Global variables like N, numOfCycles, and startProcess are not shared between these processes—each one gets its own independent copy. Your logic relies on these variables being updated across the ring, which simply won't happen.

3. Parent Process Gets Stuck on wait(NULL)

In the parent branch, you call wait(NULL) right after forking. This forces the parent to wait for the child to exit before proceeding—but your child doesn't exit immediately (it either execls another process or waits for signals). The parent gets stuck here, never entering the sigsuspend loop to receive signals.

4. Broken execl Argument for N

You convert N to a single character with char narg = N+'0';. This only works for single-digit values of N (0-9). For any N > 9, this produces invalid characters, and atoi will fail when the new process tries to read it.


Fixed Working Implementation

Here's a revised version that fixes all these issues. We'll build the ring properly by passing known PIDs between processes, avoid global variable dependencies, and fix synchronization:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int remaining_cycles;
pid_t next_pid;
pid_t my_pid;

void handle_signal(int sig) {
    if (remaining_cycles > 0) {
        printf("PID %d received signal, %d cycles left\n", my_pid, remaining_cycles);
        remaining_cycles--;
        // Forward signal to the next process in the ring
        kill(next_pid, SIGUSR1);
    } else {
        printf("PID %d finished all cycles, exiting\n", my_pid);
        exit(0);
    }
}

// Recursive helper to build the process ring
pid_t create_ring(int num_procs, pid_t root_pid, int cycles) {
    if (num_procs == 1) {
        // Last process: next PID is the root (original parent)
        next_pid = root_pid;
        remaining_cycles = cycles;
        my_pid = getpid();
        printf("Created last process %d, next is root %d\n", my_pid, root_pid);

        // Set up signal handler
        struct sigaction sa;
        sa.sa_handler = handle_signal;
        sa.sa_flags = SA_RESTART;
        sigemptyset(&sa.sa_mask);
        sigaction(SIGUSR1, &sa, NULL);

        // Wait for signals
        while (1) {
            pause();
        }
    } else {
        pid_t child = fork();
        if (child == 0) {
            // Child creates the next process in the ring
            return create_ring(num_procs - 1, root_pid, cycles);
        } else {
            // Parent's next PID is its child
            next_pid = child;
            remaining_cycles = cycles;
            my_pid = getpid();
            printf("Created process %d, next is %d\n", my_pid, child);

            // Set up signal handler
            struct sigaction sa;
            sa.sa_handler = handle_signal;
            sa.sa_flags = SA_RESTART;
            sigemptyset(&sa.sa_mask);
            sigaction(SIGUSR1, &sa, NULL);

            // Wait for signals
            while (1) {
                pause();
            }
        }
    }
    return 0;
}

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <number_of_processes> <number_of_cycles>\n", argv[0]);
        exit(1);
    }

    int num_procs = atoi(argv[1]);
    int cycles = atoi(argv[2]);
    pid_t root_pid = getpid();

    if (num_procs < 1) {
        fprintf(stderr, "Number of processes must be at least 1\n");
        exit(1);
    }

    if (num_procs == 1) {
        // Single process: signal loops back to itself
        remaining_cycles = cycles;
        my_pid = root_pid;
        next_pid = root_pid;
        printf("Single process %d, starting cycles\n", my_pid);

        struct sigaction sa;
        sa.sa_handler = handle_signal;
        sa.sa_flags = SA_RESTART;
        sigemptyset(&sa.sa_mask);
        sigaction(SIGUSR1, &sa, NULL);

        // Trigger initial signal
        kill(root_pid, SIGUSR1);
        while (1) {
            pause();
        }
    } else {
        // Build the ring and trigger the initial signal
        create_ring(num_procs, root_pid, cycles);
        kill(next_pid, SIGUSR1);

        // Clean up child processes once all cycles are done
        while (wait(NULL) > 0);
    }

    return 0;
}

Key Improvements:

  • Proper Ring Setup: We use recursion to create a chain of processes where each parent knows its child's PID, and the last child knows the root PID—forming a reliable ring.
  • No Guesswork on PIDs: Every process receives the exact PID of the next process in the ring, so signals are always sent to the right place.
  • Correct Synchronization: Processes set up their signal handlers before entering wait loops, so signals are never lost. The root process only waits for children to exit after all cycles complete.
  • Robust Argument Handling: No more broken single-character conversions for process counts.

How to Run

  1. Compile: gcc -o circle circle.c
  2. Execute with your desired parameters: ./circle 3 5 (3 processes, 5 full signal passes around the ring)

You'll see each process receive the signal, decrement the cycle count, and forward it until all cycles are completed.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 19:07:38