it-swarm-ko.tech

pthread_cond_wait 대 세마포

pthread_cond_wait 사용 또는 세마포어 사용의 장단점은 무엇입니까? 다음과 같은 상태 변경을 기다리고 있습니다.

pthread_mutex_lock(&cam->video_lock);
while(cam->status == WAIT_DISPLAY) {
    pthread_cond_wait(&cam->video_cond, &cam->video_lock);
}
pthread_mutex_unlock(&cam->video_lock);

적절하게 초기화 된 세마포어를 사용하면 다음과 같이 할 수 있다고 생각합니다.

while(cam->status == WAIT_DISPLAY) {
    sem_wait(&some_semaphore);
}

각 방법의 장단점은 무엇입니까?

45
shodanex

세마포어는 다른 용도가 있지만 생산자-소비자 모델에 깔끔하게 적합합니다. 프로그램 로직은 대기 횟수에 대해 올바른 수의 게시물이 작성되도록하는 책임이 있습니다. 세마포어를 게시했는데 아직 아무도 기다리고 있지 않다면 기다릴 때 즉시 계속됩니다. 세마포어의 개수 값으로 설명 할 수있는 문제라면 세마포어로 쉽게 해결할 수 있습니다.

조건 변수는 어떤면에서 좀 더 관대합니다. 예를 들어 생산자가 얼마나 많은지 모를 때 cond_broadcast를 사용하여 모든 웨이터를 깨울 수 있습니다. 그리고 아무도 대기하지 않는 condvar를 cond_signal하면 아무 일도 일어나지 않습니다. 듣는 사람이 관심을 가질 지 모르는 경우에 좋습니다. 또한 리스너가 항상 대기 전에 뮤텍스를 보유한 상태를 확인해야하는 이유입니다. 그렇지 않으면 신호를 놓칠 수 있고 다음 신호까지 깨어나지 않을 수 있습니다.

따라서 조건 변수는 상태가 변경되었음을 이해 당사자에게 알리는 데 적합합니다. 뮤텍스를 획득하고, 상태를 변경하고, condvar를 신호 (또는 브로드 캐스트)하고 뮤텍스를 해제합니다. 이것이 당신의 문제를 설명한다면 당신은 condvar 영역에 있습니다. 서로 다른 청취자가 서로 다른 상태에 관심이있는 경우 방송 만하면 각각 깨어나고 원하는 상태를 찾았는지 확인한 다음 다시 기다리지 않을 것입니다.

뮤텍스와 세마포어로 이런 종류의 것을 시도하는 것은 참으로 형편없는 일입니다. 문제는 뮤텍스를 사용하고 일부 상태를 확인한 다음 세마포어에서 변경 사항을 기다리려는 경우에 발생합니다. 뮤텍스를 원자 적으로 해제하고 세마포어에서 기다릴 수없는 경우 (pthread에서는 할 수 없음), 뮤텍스를 유지하는 동안 세마포어에서 대기하게됩니다. 이것은 뮤텍스를 차단하므로 다른 사람들이 당신이 관심을 갖는 변경을 할 수 없다는 것을 의미합니다. 따라서 특정 요구 사항에 따라 다른 뮤텍스를 추가하고 싶을 것입니다. 그리고 또 다른 세마포어. 결과는 일반적으로 유해한 경쟁 조건이있는 잘못된 코드입니다.

Cond_wait를 호출하면 자동으로 뮤텍스를 해제하여 다른 사용자가 사용할 수 있도록 조건 변수가이 문제를 피할 수 있습니다. cond_wait가 반환되기 전에 뮤텍스가 다시 획득됩니다.

IIRC는 세마포어 만 사용하여 일종의 condvar를 구현할 수 있지만 condvar와 함께 사용하기 위해 구현하는 뮤텍스가 trylock을 가져야하는 경우 심각한 헤드 스크래 처이며 시간 제한 대기가 종료됩니다. 권장하지 않습니다. 따라서 condvar로 수행 할 수있는 모든 작업이 세마포어로 수행 될 수 있다고 가정하지 마십시오. 물론 뮤텍스는 세마포어에 부족한 Nice 동작, 주로 우선 순위 반전 회피를 가질 수 있습니다.

62
Steve Jessop

조건문을 사용하면 세마포가 수행하지 않는 작업을 수행 할 수 있습니다.

예를 들어 m라는 뮤텍스가 필요한 코드가 있다고 가정합니다. 그러나 다른 스레드가 작업을 완료 할 때까지 기다려야하므로 s라는 세마포어를 기다립니다. 이제 m가있는 스레드가 m에서 대기 중임에도 불구하고 s이 필요한 모든 스레드는 실행이 차단됩니다. 이러한 종류의 상황은 조건문을 사용하여 해결할 수 있습니다. 조건부에서 대기하면 현재 보유 된 뮤텍스가 해제되므로 다른 스레드가 뮤텍스를 획득 할 수 있습니다. 다시 예로 돌아가서 c 대신 조건부 s이 사용되었다고 가정합니다. 스레드는 이제 m를 획득 한 다음 c에서 조건부 대기를합니다. 이것은 다른 스레드가 진행할 수 있도록 m을 릴리스합니다. c이 (가) 사용 가능 해지면 m이 (가) 다시 획득되고 원래 스레드가 계속해서 즐겁게 진행될 수 있습니다.

조건부 변수를 사용하면 pthread_cond_broadcast를 통해 진행하기 위해 조건부 변수를 기다리는 스레드가 all 스레드가 진행되도록 할 수도 있습니다. 또한 timed wait를 수행 할 수 있으므로 영원히 기다리지 않습니다.

물론 때로는 조건부 변수가 필요하지 않으므로 요구 사항에 따라 둘 중 하나가 더 나을 수 있습니다.

19
freespace

두 번째 스 니펫은 선정적입니다. 그러지 마세요.

다른 답변에는 상대적인 장점에 대한 좋은 토론이 있습니다. pthread_cond_broadcast가 조건 변수의 분명한 이점이라는 점을 추가하겠습니다.

그 외에도 Java에서 사용하는 변수이므로 공유 플래그를 확인할 때 경합을 피하는 데 도움이되기 때문에 변수를 조건화하는 데 더 익숙합니다.

실제로 두 번째 스 니펫에는 cam-> status 읽기를 보호하는 잠금이 없으므로 데이터 경쟁을 통해 액세스됩니다. 대부분의 플랫폼은이 특정 예제에서 벗어날 수 있지만 POSIX 및 다음 C/C++ 표준의 메모리 모델에 의해 정의되지 않은 의미가 있습니다.

실제로 다른 스레드가 새 캠 구조를 할당하고 캠을 덮어 쓰면 실제 경쟁 조건이 가능합니다. 대기중인 스레드는 cam-> status의 초기화를 보지 않고 'cam'포인터에 대한 업데이트를 볼 수 있습니다. 실제로 두 번째 스 니펫은이 경우 및 일반적으로 문제를 요청합니다.

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/

5
Blaisorblade

두 번째 스 니펫에서는 잠금을 해제하지 않고 여러 번 잠금을 얻습니다.

일반적으로, 당신이 waintin하고있는 상태는 세마포어로 완전히 표현 될 수 있고, 당신은 그것을 사용할 수 있습니다. 잠금 구조는 크기가 더 작고 확인/설정/해제하는 데 필요한 원자 적 작업이 적습니다.

그렇지 않고 상태가 복잡하고 코드의 다른 부분이 동일한 변수의 다른 조건에서 대기하는 경우 (예 : 여기서 x <10을 원하고 y> x를 원합니다) cond_wait를 사용합니다.

0
Javier