setpgid
POSIX C प्रक्रिया समूह न्यूनतम उदाहरण
अंतर्निहित एपीआई के न्यूनतम रननीय उदाहरण के साथ समझना आसान हो सकता है।
यह दिखाता है कि बच्चे को सिग्नल कैसे भेजा जाता है, अगर बच्चा अपने प्रक्रिया समूह को नहीं बदलता है setpgid
।
main.c
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
volatile sig_atomic_t is_child = 0;
void signal_handler(int sig) {
char parent_str[] = "sigint parent\n";
char child_str[] = "sigint child\n";
signal(sig, signal_handler);
if (sig == SIGINT) {
if (is_child) {
write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
} else {
write(STDOUT_FILENO, parent_str, sizeof(parent_str) - 1);
}
}
}
int main(int argc, char **argv) {
pid_t pid, pgid;
(void)argv;
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
pid = fork();
assert(pid != -1);
if (pid == 0) {
is_child = 1;
if (argc > 1) {
/* Change the pgid.
* The new one is guaranteed to be different than the previous, which was equal to the parent's,
* because `man setpgid` says:
* > the child has its own unique process ID, and this PID does not match
* > the ID of any existing process group (setpgid(2)) or session.
*/
setpgid(0, 0);
}
printf("child pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)getpgid(0));
assert(kill(getppid(), SIGUSR1) == 0);
while (1);
exit(EXIT_SUCCESS);
}
/* Wait until the child sends a SIGUSR1. */
pause();
pgid = getpgid(0);
printf("parent pid, pgid = %ju, %ju\n", (uintmax_t)getpid(), (uintmax_t)pgid);
/* man kill explains that negative first argument means to send a signal to a process group. */
kill(-pgid, SIGINT);
while (1);
}
गिटहब ऊपर ।
संकलन:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wpedantic -o setpgid setpgid.c
बिना भागो setpgid
बिना किसी CLI तर्क के, setpgid
नहीं किया जाता है:
./setpgid
संभावित परिणाम:
child pid, pgid = 28250, 28249
parent pid, pgid = 28249, 28249
sigint parent
sigint child
और कार्यक्रम लटक गया।
जैसा कि हम देख सकते हैं, दोनों प्रक्रियाओं का pgid एक जैसा है, क्योंकि यह विरासत में मिला है fork
।
फिर जब भी आप मारा:
Ctrl + C
यह फिर से आउटपुट करता है:
sigint parent
sigint child
यह दिखाता है कि:
- के साथ एक संपूर्ण प्रक्रिया समूह को संकेत भेजने के लिए
kill(-pgid, SIGINT)
- टर्मिनल पर Ctrl + C डिफ़ॉल्ट रूप से संपूर्ण प्रक्रिया समूह को एक किल भेजता है
दोनों प्रक्रियाओं, जैसे SIGQUIT के साथ एक अलग संकेत भेजकर कार्यक्रम से बाहर निकलें Ctrl + \
।
साथ दौड़ो setpgid
यदि आप तर्क के साथ चलते हैं, जैसे:
./setpgid 1
तब बच्चा अपना pgid बदलता है, और अब केवल माता-पिता से हर बार केवल एक ही हस्ताक्षर छपता है:
child pid, pgid = 16470, 16470
parent pid, pgid = 16469, 16469
sigint parent
और अब, जब भी आप मारा:
Ctrl + C
केवल अभिभावक ही संकेत प्राप्त करता है:
sigint parent
आप अभी भी माता-पिता को पहले की तरह मार सकते हैं:
Ctrl + \
हालाँकि बच्चे के पास अब एक अलग पीजीआईडी है, और वह संकेत प्राप्त नहीं करता है! इससे देखा जा सकता है:
ps aux | grep setpgid
आपको इसे स्पष्ट रूप से मारना होगा:
kill -9 16470
इससे यह स्पष्ट हो जाता है कि सिग्नल समूह क्यों मौजूद हैं: अन्यथा हमें हर समय मैन्युअल रूप से साफ होने वाली प्रक्रियाओं का एक गुच्छा मिलेगा।
उबंटू 18.04 पर परीक्षण किया गया।