如何向进程组内除发送进程外的所有进程发送信号?
Great question! The kill(0, SIGUSR1) trick is super handy for broadcasting signals to your entire process group, but excluding yourself requires a bit more work since there’s no direct system call that does this out of the box. Let’s walk through the most reliable approaches, plus a quick hack if you’re in a pinch.
This method involves explicitly finding every process in your group except your own, then sending the signal to each one individually. It’s the most reliable because it avoids race conditions and doesn’t interfere with your signal handling. Here’s how to implement it in C:
#include <stdio.h> #include <stdlib.h> #include <dirent.h> #include <sys/types.h> #include <signal.h> #include <unistd.h> #include <ctype.h> #include <string.h> int main() { pid_t my_pid = getpid(); pid_t my_pgid = getpgrp(); // getpgid(0) works too // Open the /proc directory to scan running processes DIR *proc_dir = opendir("/proc"); if (!proc_dir) { perror("Failed to open /proc"); return EXIT_FAILURE; } struct dirent *entry; while ((entry = readdir(proc_dir)) != NULL) { // Skip non-numeric entries (only numeric dirs are process IDs) if (!isdigit(entry->d_name[0])) { continue; } pid_t current_pid = atoi(entry->d_name); if (current_pid == my_pid) { continue; // Skip our own process } // Check if this process is in our process group pid_t current_pgid = getpgid(current_pid); if (current_pgid == -1) { // Process might have exited between scanning /proc and calling getpgid continue; } if (current_pgid == my_pgid) { // Send SIGUSR1 to the matching process if (kill(current_pid, SIGUSR1) == -1) { fprintf(stderr, "Failed to send signal to PID %d: ", current_pid); perror(""); } } } closedir(proc_dir); return EXIT_SUCCESS; }
Key notes about this code:
- We use
/proc(a pseudo-filesystem that exposes process details) to find all running processes. getpgid()checks if a process belongs to our group. Processes might exit right after we detect them, so we gracefully skip any errors fromgetpgid()orkill().- This works on all Linux systems (and most Unix-like systems with
/procsupport).
If you want a simpler solution and don’t mind a small risk, you can temporarily ignore SIGUSR1 before calling kill(0, SIGUSR1). This way, the signal is sent to your entire group (including you), but your process won’t react to it.
Here’s the code:
#include <signal.h> #include <unistd.h> #include <stdio.h> int main() { struct sigaction original_handler; // Save our original SIGUSR1 handler first if (sigaction(SIGUSR1, NULL, &original_handler) == -1) { perror("Failed to save original handler"); return EXIT_FAILURE; } // Temporarily ignore SIGUSR1 struct sigaction ignore_action = {0}; ignore_action.sa_handler = SIG_IGN; if (sigaction(SIGUSR1, &ignore_action, NULL) == -1) { perror("Failed to set ignore handler"); return EXIT_FAILURE; } // Broadcast to the process group (we'll ignore our own signal) kill(0, SIGUSR1); // Restore the original signal handler if (sigaction(SIGUSR1, &original_handler, NULL) == -1) { perror("Failed to restore original handler"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
Caveats to watch out for:
- Race condition: If another process sends
SIGUSR1to you while you’re ignoring it, you’ll miss that signal entirely. - This only prevents your handler from running—it doesn’t stop the signal from being delivered. If the signal’s default action was termination (like
SIGTERM), this wouldn’t save you (butSIGUSR1is user-defined, so this is usually safe).
If you’re working in a bash/zsh shell, you can use pkill to do this in one line:
# Get our process group ID and trim whitespace PGID=$(ps -o pgid= $$ | xargs) # Send SIGUSR1 to all processes in the group except our own pkill -g "$PGID" -v -p $$ -USR1
Breakdown of the pkill flags:
-g "$PGID": Target all processes in our process group-v: Invert the match (exclude the PID we specify)-p $$: Exclude our own shell process (PID stored in$$)-USR1: Send theSIGUSR1signal
内容的提问来源于stack exchange,提问作者Zeno Raiser

