pthread_cond_wait에는 왜 가짜 웨이크 업이 있습니까?


145

매뉴얼 페이지를 인용하려면 :

조건 변수를 사용할 때 스레드가 계속 진행되어야하는 각 조건 대기와 연관된 공유 변수와 관련된 부울 술어가 항상 있습니다. pthread_cond_timedwait () 또는 pthread_cond_wait () 함수에서 가짜 웨이크 업이 발생할 수 있습니다. pthread_cond_timedwait () 또는 pthread_cond_wait ()의 리턴은이 술어 값에 대해 아무 것도 암시하지 않으므로 해당 리턴시 술어를 다시 평가해야합니다.

그래서, pthread_cond_wait당신이 그것을 신호하지 않은 경우에도 반환 할 수 있습니다. 언뜻보기에는 꽤 끔찍한 것 같습니다. 그것은 잘못된 값을 무작위로 반환하거나 실제로 올바른 반환 문에 도달하기 전에 무작위로 반환되는 함수와 같습니다. 큰 버그 인 것 같습니다. 그러나 그들이 수정하기보다는 매뉴얼 페이지에서 이것을 문서화하기로 선택했다는 사실은 pthread_cond_wait가짜로 깨어나는 이유가 합법적 인 이유가 있음을 나타냅니다 . 아마도 도움이 될 수 없도록 작동하는 방식에 본질적인 것이 있습니다. 문제는 무엇입니까.

않는 pthread_cond_wait가짜로 복귀? 신호가 올 바르면 깨어날 것이라고 보장 할 수없는 이유는 무엇입니까? 누구나 가짜 행동의 이유를 설명 할 수 있습니까?


5
프로세스가 신호를 잡을 때마다 반환하는 것과 관련이 있다고 생각합니다. 대부분의 * nix는 신호가 중단 된 후에 차단 호출을 다시 시작하지 않습니다. 신호가 발생했다는 오류 코드를 설정 / 반환합니다.
cHao

1
@cHao : 조건 변수 에 가짜 웨이크 업 이 발생하는 다른 이유 가 있기 때문에 신호를 처리하는 것은 오류가 아닙니다 pthread_cond_(timed)wait. "신호가 전달되면 ... 중단되지 않거나 스퓨리어스 웨이크로 인해 0을 반환합니다. " 다른 차단 기능은 EINTR신호에 의해 중단 read되거나 (예 :) 재개해야하는 경우 (예 :)를 나타냅니다 pthread_mutex_lock. 따라서 가짜 웨이크 업에 대한 다른 이유가 없다면 두 가지 pthread_cond_wait중 하나로 정의 될 수 있습니다.
Steve Jessop

4
위키 백과에 관련 기사 : 가짜 웨이크
Palec


많은 기능이 작업을 완전히 수행 할 수 없으며 (인터럽트 된 I / O) 관찰 기능은 변경이 취소되거나 되돌려 진 디렉토리의 변경과 같은 비 이벤트를 수신 할 수 있습니다. 뭐가 문제 야?
curiousguy

답변:


77

다음 설명은 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] ----- / 


22
기본적으로 이것은 아무 것도 말하지 않습니다. 여기에는 "일을 더 빨리 할 수있다"는 초기 생각 외에는 설명이 없지만, 그것이 어떻게 또는 어떻게되는지 전혀 모른다.
Bogdan Ionitza

107

'스퓨리어스 웨이크 업'이 의미 할 수있는 최소한 두 가지가 있습니다.

  • 스레드는에 차단 pthread_cond_wait에는 호출에도 호출에서 반환 할 수 있습니다 pthread_call_signal또는 pthread_cond_broadcast조건으로는 발생하지 않았다.
  • 스레드 pthread_cond_waitpthread_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는 조건을 다시 기다려야합니다.

따라서 루프에서 항상 술어를 점검해야하므로 기본 조건 변수에 다른 종류의 스퓨리어스 웨이크 업이있을 수 있으면 차이가 없습니다.


23
예. 본질적으로, 이는 카운트가있는 동기화 메커니즘 대신 이벤트가 사용될 때 발생합니다. 안타깝게도 POSIX 세마포어 (리눅스의 경우)는 가려움증을 유발하는 것으로 보입니다. 동기화 프리미티브의 기본 기능 실패가 '정상'으로 받아 들여지고 사용자 수준에서 해결되어야한다는 것이 조금 이상하다는 것을 알았습니다. (아마도 시스템 호출이 문서화되면 개발자가 무기를 썼을 것입니다. '의심스러운 segfault'섹션 또는 '잘못된 URL에 대한 의심스러운 연결'또는 '잘못된 파일의 의심스러운 열기'와 함께
Martin James

2
"스퓨리어스 웨이크 업"의보다 일반적인 시나리오는 pthread_cond_broadcast () 호출의 부작용 일 가능성이 높습니다. 5 개의 스레드 풀이 있고 두 개가 브로드 캐스트로 일어나서 작업을 수행한다고 가정 해 봅시다. 다른 세 사람은 일어나서 작업이 완료된 것을 발견했습니다. 다중 프로세서 시스템으로 인해 우연히 여러 스레드를 깨우는 조건부 신호가 발생할 수 있습니다. 코드는 단지 술어를 다시 점검하고, 유효하지 않은 상태를보고 다시 휴면 상태로 돌아갑니다. 두 경우 모두 술어를 점검하면 문제점이 해결됩니다. 일반적으로 IMO는 원시 POSIX 뮤텍스와 조건을 사용하지 않아야합니다.
CubicleSoft

1
@MartinJames-고전적인 "스퓨리어스"EINTR은 어떻습니까? 루프에서 EINTR을 지속적으로 테스트하는 것은 귀찮고 코드를 추악하게 만들지 만 개발자는 임의의 손상을 피하기 위해 어쨌든 수행한다는 데 동의합니다.
CubicleSoft

2
@Yola 아니요 뮤텍스를 잠 가야하기 때문에 pthread_cond_signal/broadcast뮤텍스를 잠금 해제 할 때까지 호출 할 수 없기 때문에 불가능합니다 pthread_cond_wait.
a3f

1
이 답변의 예는 매우 현실적이며 조건자를 확인하는 것이 좋습니다. 그러나 "스레드 1이 현재 작업을 완료하고 더 많은 작업을 위해 대기열로 돌아갑니다"라는 문제가있는 단계를 수행하여 스레드를 "스레드 1이 현재 작업을 완료하고 다시 대기 중으로 돌아가서 동일하게 고정시킬 수 없었습니다. 조건 변수 "? 그렇게하면 대답에 설명 된 실패 모드가 제거되고 가짜 웨이크가 없으면 코드가 올바르게 작성 됩니다. 실제로 가짜 웨이크 업을 발생시키는 실제 구현이 있습니까?
Quuxplusone

7

pthread_cond_signal의 "조건 신호에 의한 다중 깨우기"절 에는 가짜 wakekups를 포함하는 pthread_cond_wait 및 pthread_cond_signal의 구현 예제가 있습니다.


2
나는이 대답이 잘못되었다고 생각합니다. 해당 페이지의 샘플 구현에는 "모두 알림"과 동등한 "하나에 알림"구현이 있습니다. 그러나 실제로 가짜 모닝콜 을 생성하지 않는 것 같습니다 . 스레드가 깨우는 유일한 방법은 다른 스레드가 "모두 알림"을 ​​호출하거나 다른 스레드가 레이블이있는 "하나에 알림"-실제로- "모두 알림"을 ​​호출하는 것입니다.
Quuxplusone

5

디자인 시점에 고려되지는 않았지만 실제 기술적 인 이유는 다음과 같습니다. 스레드 취소와 함께, "스퓨리어스"를 깨우는 옵션을 선택해야하는 경우가 있습니다. '어떤 종류의 구현 전략이 가능한지에 대해 매우 강력한 제약을 가할 것입니다.

핵심 문제는에서 차단 된 상태에서 스레드가 취소에 작용할 경우 pthread_cond_wait부작용은 마치 조건 변수에서 신호를 소비하지 않은 것처럼 발생해야한다는 것입니다. 그러나 취소 작업을 시작할 때 아직 신호를 소비하지 않았는지 확인하기가 어렵고 제한적입니다.이 단계에서 신호를 조건 변수에 "재 게시"하는 것이 불가능할 수 있습니다. 호출자 pthread_cond_signal가 이미 콘드 바를 파괴하고 그것이 존재하는 메모리를 비운 것으로 정당화 되는 상황 에 있어야한다.

스퓨리어스 웨이크에 대한 허용은 당신에게 쉽게 밖으로 제공합니다. 조건 변수에서 차단 된 상태에서 도착할 때 취소에 계속 행동하는 대신, 이미 신호를 소비했거나 게으 르기를 원한다면 가짜 일어났다 고 선언 할 수 있습니다. 성공으로 돌아갑니다. 올바른 호출자가 다음에 반복해서 pthread_cond_wait다시 호출 할 때 보류중인 취소에 대해 조치를 취하기 때문에 이는 취소 작업을 전혀 방해하지 않습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.