부모 프로세스에서 자식 프로세스 종료하기 질문 입니다.
글쓴이: 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를 시도하다가 실패하는 것이고요.
그렇군요!
답변 감사합니다.
연습문제는 이제부터 풀어보도록 하겠습니다. ^^
연습문제 풀었습니다.
이게 제일 좋은 방법인지는 모르겠지만, 일단은 아래와 같이 고치고 나니 문제는 없어졌습니다.
추가질문이 생겼습니다.
일단 익명님이 주신 힌트로 원래의 문제는 없어졌습니다.
하지만, 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로 할당된 메모리를 해제해 줄 필요가 없는 것과 마찬가지지요.
댓글 달기