부모 프로세스에서 자식 프로세스 종료하기 질문 입니다.
글쓴이: study / 작성시간: 토, 2022/01/15 - 10:18오후
프로세스를 4개 만들고, 그 중 부모 프로세스에서 자식 프로세스를 종료시키는 걸 해보고 있었습니다.
이해가 안갔던 부분은 252번째줄 ~ 266번쨰줄의 내용을 포함시키면, 아래와 같은 에러가 나네요.
프로그램이름이 kill_wait2입니다.
# ./kill_wait2 child_process2-1 : 2230 child_process1-1 : 2229 child_process3-1 : 2231 printed from parent process - 2228 printed from parent process - pids->parent = 2228 printed from parent process - pids->child1 = 2229 printed from parent process - pids->child2 = 2230 printed from parent process - pids->child3 = 2231 waitpid: No child processes
252번째줄 ~ 266번쨰줄의 내용을 아래 코드처럼 #if 0로 막아놓으면, 아래와 같이 예상대로 실행이 됩니다.
# ./kill_wait2 child_process2-1 : 2260 child_process1-1 : 2259 child_process3-1 : 2261 printed from parent process - 2258 printed from parent process - pids->parent = 2258 printed from parent process - pids->child1 = 2259 printed from parent process - pids->child2 = 2260 printed from parent process - pids->child3 = 2261 Enter exit stop : exit parent-process : end of while parent-process : exiting
전체 예제 소스는 아래와 같습니다.
잘못된 부분을 영 못찾고 있네요.
조언부탁드립니다!
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <unistd.h>
6 #include <sys/wait.h>
7 #include <signal.h>
8
9 #include <sys/wait.h>
10 #include <sys/ipc.h>
11 #include <sys/shm.h>
12
13 #define SHM_KEY 0x9997
14 struct _process_ids {
15 pid_t parent;
16 pid_t child1;
17 pid_t child2;
18 pid_t child3;
19 };
20 typedef struct _process_ids Process_ID_t;
21
22 volatile sig_atomic_t shutdown_flag = 1;
23
24 void cleanupRoutine(int32_t signal_number)
25 {
26 shutdown_flag = 0;
27 }
28
29 int32_t child_process1(void)
30 {
31 int32_t count = 0;
32 int32_t ret;
33 struct sigaction sigterm_action;
34 int32_t shmid;
35 Process_ID_t *pids;
36
37 printf("child_process1-1 : %ld\n", getpid());
38 shmid = shmget(SHM_KEY, sizeof(Process_ID_t), 0644|IPC_CREAT);
39 if (shmid == -1)
40 {
41 perror("Shared Memory");
42 return -1;
43 }
44
45 pids = shmat(shmid, NULL, 0);
46 if (pids == (void *)-1)
47 {
48 perror("Shared Memory Attach");
49 return -1;
50 }
51
52 pids->child1 = getpid();
53
54 memset(&sigterm_action, 0x0, sizeof(struct sigaction));
55 sigterm_action.sa_handler = &cleanupRoutine;
56 sigterm_action.sa_flags = 0;
57
58 ret = sigfillset(&sigterm_action.sa_mask);
59 if (ret != 0)
60 {
61 perror("sigaction SIGTERM");
62 exit(EXIT_FAILURE);
63 }
64
65 while (shutdown_flag)
66 {
67 count++;
68 // printf("child1 : count = %d\n", count);
69 sleep(1);
70 }
71 printf("child_process1-2\n");
72
73 ret = shmdt(pids);
74 if (ret == -1)
75 {
76 perror("Share Memory Detach");
77 return -1;
78 }
79
80 exit(EXIT_SUCCESS);
81 }
82
83 int32_t child_process2(void)
84 {
85 int32_t count = 0;
86 int32_t ret;
87 struct sigaction sigterm_action;
88 int32_t shmid;
89 Process_ID_t *pids;
90
91 printf("child_process2-1 : %ld\n", getpid());
92 shmid = shmget(SHM_KEY, sizeof(Process_ID_t), 0644|IPC_CREAT);
93 if (shmid == -1)
94 {
95 perror("Shared Memory");
96 return -1;
97 }
98
99 pids = shmat(shmid, NULL, 0);
100 if (pids == (void *)-1)
101 {
102 perror("Shared Memory Attach");
103 return -1;
104 }
105
106 pids->child2 = getpid();
107
108 memset(&sigterm_action, 0x0, sizeof(struct sigaction));
109 sigterm_action.sa_handler = &cleanupRoutine;
110 sigterm_action.sa_flags = 0;
111
112 ret = sigfillset(&sigterm_action.sa_mask);
113 if (ret != 0)
114 {
115 perror("sigaction SIGTERM");
116 exit(EXIT_FAILURE);
117 }
118
119 while (shutdown_flag)
120 {
121 count++;
122 // printf("child2 : count = %d\n", count);
123 sleep(1);
124 }
125 printf("child_process2-2\n");
126
127 ret = shmdt(pids);
128 if (ret == -1)
129 {
130 perror("Share Memory Detach");
131 return -1;
132 }
133
134 exit(EXIT_SUCCESS);
135 }
136
137 int32_t child_process3(void)
138 {
139 int32_t count = 0;
140 int32_t ret;
141 struct sigaction sigterm_action;
142 int32_t shmid;
143 Process_ID_t *pids;
144
145 printf("child_process3-1 : %ld\n", getpid());
146 shmid = shmget(SHM_KEY, sizeof(Process_ID_t), 0644|IPC_CREAT);
147 if (shmid == -1)
148 {
149 perror("Shared Memory");
150 return -1;
151 }
152
153 pids = shmat(shmid, NULL, 0);
154 if (pids == (void *)-1)
155 {
156 perror("Shared Memory Attach");
157 return -1;
158 }
159
160 pids->child3 = getpid();
161
162 memset(&sigterm_action, 0x0, sizeof(struct sigaction));
163 sigterm_action.sa_handler = &cleanupRoutine;
164 sigterm_action.sa_flags = 0;
165
166 ret = sigfillset(&sigterm_action.sa_mask);
167 if (ret != 0)
168 {
169 perror("sigaction SIGTERM");
170 exit(EXIT_FAILURE);
171 }
172
173 while (shutdown_flag)
174 {
175 count++;
176 // printf("child3 : count = %d\n", count);
177 sleep(1);
178 }
179 printf("child_process3-2\n");
180
181 ret = shmdt(pids);
182 if (ret == -1)
183 {
184 perror("Share Memory Detach");
185 return -1;
186 }
187
188 exit(EXIT_SUCCESS);
189 }
190
191 int32_t parent_process(void)
192 {
193 int32_t ret;
194 int32_t wstatus;
195 int32_t shmid;
196 char input[10];
197 Process_ID_t *pids;
198
199 shmid = shmget(SHM_KEY, sizeof(Process_ID_t), 0644|IPC_CREAT);
200 if (shmid == -1)
201 {
202 perror("Shared Memory");
203 return -1;
204 }
205
206 /* attach shared memory */
207 pids = shmat(shmid, NULL, 0);
208 if (pids == (void *)-1)
209 {
210 perror("Shared Memory Attach");
211 return -1;
212 }
213
214 pids->parent = getpid();
215
216 sleep(10);
217
218 printf("printed from parent process - %ld\n", getpid());
219 printf("printed from parent process - pids->parent = %ld\n", pids->parent );
220 printf("printed from parent process - pids->child1 = %ld\n", pids->child1 );
221 printf("printed from parent process - pids->child2 = %ld\n", pids->child2 );
222 printf("printed from parent process - pids->child3 = %ld\n", pids->child3 );
223
224 ret = kill(pids->child1, SIGTERM);
225 if (ret == -1)
226 {
227 perror("kill");
228 exit(EXIT_FAILURE);
229 }
230
231 ret = waitpid(pids->child1, &wstatus, WUNTRACED | WCONTINUED);
232 if (ret == -1)
233 {
234 perror("waitpid");
235 exit(EXIT_FAILURE);
236 }
237
238 ret = kill(pids->child2, SIGTERM);
239 if (ret == -1)
240 {
241 perror("kill");
242 exit(EXIT_FAILURE);
243 }
244
245 ret = waitpid(pids->child2, &wstatus, WUNTRACED | WCONTINUED);
246 if (ret == -1)
247 {
248 perror("waitpid");
249 exit(EXIT_FAILURE);
250 }
251
252 #if 0
253 ret = kill(pids->child3, SIGTERM);
254 if (ret == -1)
255 {
256 perror("kill");
257 exit(EXIT_FAILURE);
258 }
259
260 ret = waitpid(pids->child3, &wstatus, WUNTRACED | WCONTINUED);
261 if (ret == -1)
262 {
263 perror("waitpid");
264 exit(EXIT_FAILURE);
265 }
266 #endif
267
268 while (1)
269 {
270 printf("Enter exit stop : \n");
271 fgets(input, 10, stdin);
272 input[strlen(input)-1] = '\0';
273
274 ret = strncmp(input, "exit", strlen("exit"));
275 if (ret == 0)
276 {
277 break;
278 }
279 else
280 {
281 sleep(2);
282 }
283 }
284
285 printf("parent-process : end of while\n");
286 /* Detach shared memory */
287 ret = shmdt(pids);
288 if (ret == -1)
289 {
290 perror("Share Memory Detach");
291 return -1;
292 }
293
294 ret = shmctl(shmid, IPC_RMID, 0);
295 if (ret == -1)
296 {
297 perror("shmctl");
298 return -1;
299 }
300
301 printf("parent-process : exiting\n");
302 exit(EXIT_SUCCESS);
303 }
304
305 int32_t main(void)
306 {
307 pid_t p1, p2;
308
309 p1 = fork();
310 p2 = fork();
311
312 if (p1 > 0 && p2 > 0)
313 {
314 parent_process();
315 }
316 else if (p1 == 0 && p2 > 0)
317 {
318 child_process1();
319 }
320 else if (p1 > 0 && p2 == 0)
321 {
322 child_process2();
323 }
324 else
325 {
326 child_process3();
327 }
328
329 exit(0);
330 }Forums:


족보가 꼬였기 때문입니다.
족보가 꼬였기 때문입니다.
1. 주어진 상황이 parent_process가 세 개의 children processes를 가진 상황이라고 생각하셨다면, 틀렸습니다.
parent_process는 두 children (child_process1, child_process2)만 가지고 있습니다.
child_process3은 child_process1의 child 이지요.
왜 그렇게 되는지는 가계도를 직접 그려 보면 금방 알 수 있는데, 연습 문제로 남깁니다.
2. 미묘한 차이입니다만, 그 결과 이 코드에서 parent_process가 child_process3을 wait 할 수 없게 만듭니다.
실제로 일어난 일은 아래와 같지요.
우선, child_process3의 parent인 child_process1는 parent_process에 의해 먼저 죽습니다.
고아가 된 child_process3은 init이 거두게 되고, parent_process가 마침내 child_process3도 죽였을 때,
init이 child_process3을 wait 해서 정리해 버리게 됩니다.
parent_process는 자기 자식인 줄 알았던 child_process3이 사실은 손자였다는 것을 끝내 깨닫지 못하고 wait를 시도하다가 실패하는 것이고요.
그렇군요!
답변 감사합니다.
연습문제는 이제부터 풀어보도록 하겠습니다. ^^
연습문제 풀었습니다.
이게 제일 좋은 방법인지는 모르겠지만, 일단은 아래와 같이 고치고 나니 문제는 없어졌습니다.
int32_t main(void) { pid_t child1, child2, child3; child1 = fork(); if (child1 == 0) { child_process1(); } child2 = fork(); if (child2 == 0) { child_process2(); } child3 = fork(); if (child3 == 0) { child_process3(); } parent_process(); exit(0); }추가질문이 생겼습니다.
일단 익명님이 주신 힌트로 원래의 문제는 없어졌습니다.
하지만, child_process1(), child_process2(), child_process3()안에서의 while_loop 뒤에
printf("child_process1-2\n"), printf("child_process2-2\n"), printf("child_process2-2\n")
와 같은 message를 넣어봤는데, 안 찍히네요.
그럼 이 의미는 child process들이 termination될 때, while() 이후의 코드는 수행되지 않는건가요?
그럼 제가 넣어놓은 공유메모리 해제를 위한 shmdt()들도 수행되지 않는거겠네요.
main_process()가 종료된 후에, ipcs 명령으로 조사해보면 공유메모리는 제대로 해제 되어있네요.
그럼 shm_dt()를 child_process에서 부를 필요가 없는건가요?
1. sigaction 함수 호출 안 했잖아요.
1. sigaction 함수 호출 안 했잖아요.
sigaction 구조체를 조작하는 것만으로는 부족합니다.
2. parent_process에서 IPC_RMID를 넘겨 shmctl를 호출한 순간부터, 공유 메모리의 해제는 초읽기에 들어갑니다.
해당 공유 메모리를 부착한 모든 프로세스가 (1) 종료되거나 (2) 공유 메모리를 탈착한 뒤에 실제로 해제가 됩니다.
프로세스가 곧 종료될 예정이라면 구태여 공유 메모리를 일일히 탈착할 필요는 없다는 뜻입니다.
마치 프로그램 종료 직전에 malloc/new로 할당된 메모리를 해제해 줄 필요가 없는 것과 마찬가지지요.
댓글 달기