문제
다음을 고려하십시오 fork()
/SIGCHLD
의사 코드.
// main program excerpt
for (;;) {
if ( is_time_to_make_babies ) {
pid = fork();
if (pid == -1) {
/* fail */
} else if (pid == 0) {
/* child stuff */
print "child started"
exit
} else {
/* parent stuff */
print "parent forked new child ", pid
children.add(pid);
}
}
}
// SIGCHLD handler
sigchld_handler(signo) {
while ( (pid = wait(status, WNOHANG)) > 0 ) {
print "parent caught SIGCHLD from ", pid
children.remove(pid);
}
}
위의 예에서는 경주 조건이 있습니다. 가능합니다./* child stuff */
"전에 끝내기"/* parent stuff */
"시작하여 어린이의 PID가 출발 한 후 어린이 목록에 추가 될 수 있고 제거되지 않습니다. 앱이 닫히기가되면 부모는 이미 마감 된 어린이가 끝나기 위해 끝없이 기다릴 것입니다.
이 문제를 해결하기 위해 생각할 수있는 한 가지 해결책은 두 가지 목록을 갖는 것입니다. started_children
그리고 finished_children
. 나는 추가 할 것이다 started_children
내가 추가하는 같은 장소에서 children
지금. 그러나 신호 핸들러에서 children
ID 추가하다 에게 finished_children
. 앱이 문을 닫으면 부모는 단순히 차이가있을 때까지 기다릴 수 있습니다. started_children
그리고 finished_children
0입니다.
내가 생각할 수있는 또 다른 해결책은 공유 메모리를 사용하는 것입니다. 예를 들어 부모의 자녀 목록을 공유하고 자녀를 .add
그리고 .remove
그들 자신? 그러나 나는 이것에 대해 너무 많이 모른다.
편집 : 가장 먼저 떠오르는 또 다른 가능한 솔루션은 sleep(1)
시작시 /* child stuff */
그러나 그것은 나에게 재미있는 냄새가 나기 때문에 내가 그것을 떠난 이유입니다. 나는 또한 그것이 100% 수정인지 확실하지 않습니다.
그렇다면이 경주 조건을 어떻게 수정 하시겠습니까? 그리고이를 위해 잘 확립 된 권장 패턴이 있다면 알려주십시오!
감사.
해결책
가장 간단한 솔루션은 이전에 sigchld 신호를 차단하는 것입니다 fork()
~와 함께 sigprocmask()
PID를 처리 한 후 부모 코드에서 차단 해제됩니다.
자식이 사망하면 신호를 차단 해제 한 후 Sigchld의 신호 처리기가 호출됩니다. 중요한 섹션 개념입니다 - 귀하의 경우 중요한 섹션은 이전에 시작됩니다. fork()
그리고 후에 끝납니다 children.add()
.
다른 팁
중요한 조각을 사용할 수 없다면 간단한 카운터 가이 작업을 수행 할 수 있습니다. +1을 추가 할 때, -1을 제거 할 때, 먼저 어떤 일이 발생하지 않으면, 결국 모든 것이 완료되면 0을 얻을 수 있습니다.
기존의 "어린이"외에도 새로운 데이터 구조 "조기 사망"을 추가합니다. 이것은 아이들의 내용을 깨끗하게 유지합니다.
// main program excerpt
for (;;) {
if ( is_time_to_make_babies ) {
pid = fork();
if (pid == -1) {
/* fail */
} else if (pid == 0) {
/* child stuff */
print "child started"
exit
} else {
/* parent stuff */
print "parent forked new child ", pid
if (!earlyDeaths.contains(pid)) {
children.add(pid);
} else {
earlyDeaths.remove(pid);
}
}
}
}
// SIGCHLD handler
sigchld_handler(signo) {
while ( (pid = wait(status, WNOHANG)) > 0 ) {
print "parent caught SIGCHLD from ", pid
if (children.contains(pid)) {
children.remove(pid);
} else {
earlyDeaths.add(pid);
}
}
}
편집 : 프로세스가 단일 스레드 인 경우 단순화 할 수 있습니다. EarlyDeaths는 컨테이너 일 필요가 없으며 하나의 PID를 유지하면됩니다.
낙관적 인 알고리즘일까요? 어린이를 시험해보십시오.
아니면 PID를 제거하기 전에 PID가 어린이에 있는지 확인하십시오.