[c] pthread_cond_wait에는 왜 가짜 웨이크 업이 있습니까?
매뉴얼 페이지를 인용하려면 :
조건 변수를 사용할 때 스레드가 계속 진행되어야하는 각 조건 대기와 연관된 공유 변수와 관련된 부울 술어가 항상 있습니다. pthread_cond_timedwait () 또는 pthread_cond_wait () 함수에서 가짜 웨이크 업이 발생할 수 있습니다. pthread_cond_timedwait () 또는 pthread_cond_wait ()의 리턴은이 술어 값에 대해 아무 것도 암시하지 않으므로 해당 리턴시 술어를 다시 평가해야합니다.
그래서, pthread_cond_wait
당신이 그것을 신호하지 않은 경우에도 반환 할 수 있습니다. 언뜻보기에는 꽤 끔찍한 것 같습니다. 그것은 잘못된 값을 무작위로 반환하거나 실제로 올바른 반환 문에 도달하기 전에 무작위로 반환되는 함수와 같습니다. 큰 버그 인 것 같습니다. 그러나 그들이 수정하기보다는 매뉴얼 페이지에서 이것을 문서화하기로 선택했다는 사실은 pthread_cond_wait
가짜로 깨어나는 이유가 합법적 인 이유가 있음을 나타냅니다 . 아마도 도움이 될 수 없도록 작동하는 방식에 본질적인 것이 있습니다. 문제는 무엇입니까.
왜 않는 pthread_cond_wait
가짜로 복귀? 신호가 올 바르면 깨어날 것이라고 보장 할 수없는 이유는 무엇입니까? 누구나 가짜 행동의 이유를 설명 할 수 있습니까?
답변
다음 설명은 David R. Butenhof가 “POSIX 스레드 프로그래밍” (80 페이지)에서 제공합니다.
스퓨리어스 웨이크가 이상하게 들릴 수도 있지만 일부 멀티 프로세서 시스템에서 조건 웨이크 업을 완전히 예측 가능하게하면 모든 조건 변수 작업이 상당히 느려질 수 있습니다.
다음 comp.programming.threads 토론 에서 그는 디자인의 기본 개념을 확장합니다.
Patrick Doyle은 다음과 같이 썼습니다. > 기사에서 Tom Payne은 다음과 같이 썼습니다. Kaz Kylheku는 다음과 같이 썼다. >> : 구현이 때때로 삽입을 피할 수 없기 때문에 >> :이 가짜 모닝콜; 이를 방지하는 데 비용이 많이들 수 있습니다. 그러나 왜? 왜 이렇게 어려운가요? 예를 들어서 신호가 도착하는 것처럼 대기 시간이 초과되는 상황은 무엇입니까? > pthreads 디자이너가 다음과 같은 논리를 사용했는지 궁금합니다. > 조건 변수 사용자는 종료시 조건을 확인해야합니다. > 허용 할 경우 추가 부담을주지 않습니다. > 가짜 모닝콜; 그리고 스퓨리어스를 허용하는 것을 생각할 수 있기 때문에 > 웨이크 업은 구현을 더 빠르게 할 수 있습니다. > 허용하십시오. > 특정 구현을 염두에 두지 않았을 수 있습니다. 당신은 그것을 멀리 밀지 않았다는 것을 제외하고는 실제로 전혀 멀지 않습니다. 목적은 술어 루프를 요구하여 올바른 / 강건한 코드를 작성하는 것이 었습니다. 이했다 의 "핵심 실"중에 아마도 정확한 학문적 우발에 의해 구동 실무 그룹, 나는 아무도 의도에 동의하지 않았다고 생각합니다. 일단 그들은 그것이 무엇을 의미하는지 이해했습니다. 우리는 몇 가지 수준의 정당화로 그 의도를 따랐습니다. 첫 번째는 "유연하게"루프를 사용하면 응용 프로그램 자체의 불완전 성을 방지합니다 코딩 관행. 두 번째는 추상적으로 상상하기 어렵지 않다는 것입니다 이 요구 사항을 이용하여 개선 할 수있는 기계 및 구현 코드 최적화를 통한 평균 조건 대기 작업의 성능 동기화 메커니즘. / ------------------ [David.Buten ... @ compaq.com] ------------------ \ | Compaq Computer Corporation POSIX 스레드 설계자 | | 나의 책 : http://www.awl.com/cseng/titles/0-201-63392-2/ | \ ----- [http://home.earthlink.net/~anneart/family/dave.html] ----- /
답변
‘스퓨리어스 웨이크 업’이 의미 할 수있는 최소한 두 가지가 있습니다.
- 스레드는에 차단
pthread_cond_wait
에는 호출에도 호출에서 반환 할 수 있습니다pthread_call_signal
또는pthread_cond_broadcast
조건으로는 발생하지 않았다. - 스레드
pthread_cond_wait
가pthread_cond_signal
또는 호출로 인해 리턴 에서 차단pthread_cond_broadcast
되었지만 뮤텍스를 다시 획득 한 후 기본 술어는 더 이상 사실이 아닙니다.
그러나 조건 변수 구현이 전자의 경우를 허용하지 않더라도 후자의 경우가 발생할 수 있습니다. 생산자 소비자 대기열과 3 개의 스레드를 고려하십시오.
- 스레드 1이 요소를 대기열에서 빼고 뮤텍스를 해제했으며 대기열이 비어 있습니다. 스레드는 일부 CPU에서 얻은 요소로 수행하는 모든 작업을 수행합니다.
- 스레드 2는 요소를 큐에서 제거하려고 시도하지만
pthread_cond_wait
신호 / 방송을 기다리는 호출에서 mutex, calls 및 블록에서 검사 할 때 큐가 비어있는 것을 찾습니다 . - 스레드 3은 뮤텍스를 확보하고 큐에 새 요소를 삽입하고 조건 변수에 알리고 잠금을 해제합니다.
- 스레드 3의 알림에 따라 조건을 대기중인 스레드 2가 실행되도록 예약됩니다.
- 그러나 스레드 2가 CPU에 액세스하여 큐 잠금을 가져 오기 전에 스레드 1은 현재 작업을 완료하고 더 많은 작업을 위해 큐로 돌아갑니다. 큐 잠금을 확보하고 술어를 확인한 후 큐에 작업이 있음을 발견합니다. 스레드 3이 삽입 한 항목을 큐에서 제거하고 잠금을 해제하며 스레드 3이 큐에 넣은 항목으로 수행하는 모든 작업을 수행합니다.
- 스레드 2는 이제 CPU에서 잠금을 얻지 만, 술어를 점검 할 때 큐가 비어 있음을 발견합니다. 스레드 1이 아이템을 훔쳐서 깨어 난 것으로 보입니다. 스레드 2는 조건을 다시 기다려야합니다.
따라서 루프에서 항상 술어를 점검해야하므로 기본 조건 변수에 다른 종류의 스퓨리어스 웨이크 업이있을 수 있으면 차이가 없습니다.
답변
pthread_cond_signal의 “조건 신호에 의한 다중 깨우기”절 에는 가짜 wakekups를 포함하는 pthread_cond_wait 및 pthread_cond_signal의 구현 예제가 있습니다.
답변
디자인 시점에 고려되지는 않았지만 실제 기술적 인 이유는 다음과 같습니다. 스레드 취소와 함께, “스퓨리어스”를 깨우는 옵션을 선택해야하는 경우가 있습니다. ‘어떤 종류의 구현 전략이 가능한지에 대해 매우 강력한 제약을 가할 것입니다.
핵심 문제는에서 차단 된 상태에서 스레드가 취소에 작용할 경우 pthread_cond_wait
부작용은 마치 조건 변수에서 신호를 소비하지 않은 것처럼 발생해야한다는 것입니다. 그러나 취소 작업을 시작할 때 아직 신호를 소비하지 않았는지 확인하기가 어렵고 제한적입니다.이 단계에서 신호를 조건 변수에 “재 게시”하는 것이 불가능할 수 있습니다. 호출자 pthread_cond_signal
가 이미 콘드 바를 파괴하고 그것이 존재하는 메모리를 비운 것으로 정당화 되는 상황 에 있어야한다.
스퓨리어스 웨이크에 대한 허용은 당신에게 쉽게 밖으로 제공합니다. 조건 변수에서 차단 된 상태에서 도착할 때 취소에 계속 행동하는 대신, 이미 신호를 소비했거나 게으 르기를 원한다면 가짜 일어났다 고 선언 할 수 있습니다. 성공으로 돌아갑니다. 올바른 호출자가 다음에 반복해서 pthread_cond_wait
다시 호출 할 때 보류중인 취소에 대해 조치를 취하기 때문에 이는 취소 작업을 전혀 방해하지 않습니다 .