문제

다음을 고려하십시오 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가 어린이에 있는지 확인하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top