조건부 변수 대 세마포


답변:


207

잠금은 상호 배제에 사용됩니다. 코드 조각이 원 자성인지 확인하려면 그 주위에 잠금 장치를 두십시오. 이론적으로 이진 세마포어를 사용하여이 작업을 수행 할 수 있지만 이는 특별한 경우입니다.

세마포어 및 조건 변수는 잠금에 의해 제공되는 상호 배제 위에 구축되며 공유 리소스에 대한 동기화 된 액세스를 제공하는 데 사용됩니다. 유사한 목적으로 사용할 수 있습니다.

조건 변수는 일반적으로 리소스를 사용할 수있을 때까지 기다리는 동안 바쁜 대기 (조건을 확인하는 동안 반복해서 반복)를 방지하는 데 사용됩니다. 예를 들어 큐가 비워 질 때까지 계속할 수없는 스레드 (또는 여러 스레드)가있는 경우 바쁜 대기 방식은 다음과 같은 작업을 수행하는 것입니다.

//pseudocode
while(!queue.empty())
{
   sleep(1);
}

문제는이 스레드가 조건을 반복적으로 확인하도록하여 프로세서 시간을 낭비하고 있다는 것입니다. 대신 자원을 사용할 수 있음을 스레드에 알리기 위해 신호를 보낼 수있는 동기화 변수가없는 이유는 무엇입니까?

//pseudocode
syncVar.lock.acquire();

while(!queue.empty())
{
   syncVar.wait();
}

//do stuff with queue

syncVar.lock.release();

아마도 대기열에서 물건을 꺼내는 다른 스레드가있을 것입니다. 큐가 비어 있으면 대기 syncVar.signal()중인 임의의 스레드를 깨우기 위해 호출 할 수 있습니다 syncVar.wait()(또는 일반적으로 대기중인 모든 스레드를 깨우는 signalAll()또는 broadcast()메서드 도 있습니다 ).

일반적으로 단일 특정 조건 (예 : 대기열이 비어있는 경우)에서 대기중인 스레드가 하나 이상있을 때 이와 같은 동기화 변수를 사용합니다.

세마포어도 비슷하게 사용할 수 있지만 몇 가지 정수를 기반으로 사용할 수 있고 사용할 수없는 공유 리소스가있을 때 더 잘 사용된다고 생각합니다. 세마포는 생산자가 리소스를 할당하고 소비자가이를 소비하는 생산자 / 소비자 상황에 적합합니다.

탄산 음료 자판기가 있는지 생각해보십시오. 탄산 음료 머신은 하나 뿐이며 공유 리소스입니다. 기계의 재고를 유지하는 공급 업체 (생산자) 인 스레드 하나와 기계에서 탄산 음료를 꺼내고 자하는 구매자 (소비자) 인 스레드 N 개가 있습니다. 기계의 탄산 음료 수는 세마포어를 구동하는 정수 값입니다.

소다 기계에 오는 모든 구매자 (소비자) 스레드는 세마포어 down()메서드를 호출하여 소다를 가져 옵니다 . 이렇게하면 기계에서 탄산 음료를 가져와 사용 가능한 탄산 음료의 수를 1만큼 줄입니다. 사용 가능한 탄산 음료가 있으면 코드가 down()문제없이 문을 지나 계속 실행 됩니다. 탄산 음료를 사용할 수없는 경우 스레드는 여기에서 잠자기 상태가되어 탄산 음료가 다시 사용 가능해질 때 알림을받습니다 (머신에 탄산 음료가 더있을 때).

공급 업체 (생산자) 스레드는 본질적으로 탄산 음료 기계가 비어 있기를 기다리고 있습니다. 공급 업체는 기계에서 마지막 탄산 음료를 가져 오면 알림을받습니다 (그리고 한 명 이상의 소비자가 탄산 음료를 꺼내기를 기다리고있을 가능성이 있음). 공급 업체는 세마포어 up()방법으로 소다 기계를 재입고하고 , 사용 가능한 소다 수는 매번 증가하므로 대기중인 소비자 스레드는 더 많은 소다를 사용할 수 있다는 알림을받습니다.

동기화 변수 의 wait()signal()메서드 는 세마포어 의 down()up()작업 내에 숨겨지는 경향이 있습니다 .

확실히 두 선택 사이에 겹치는 부분이 있습니다. 세마포어 또는 조건 변수 (또는 조건 변수 세트)가 모두 사용자의 목적에 부합 할 수있는 시나리오가 많이 있습니다. 세마포어와 조건 변수는 모두 상호 배제를 유지하는 데 사용하는 잠금 개체와 연결되어 있지만 스레드 실행 동기화를 위해 잠금 위에 추가 기능을 제공합니다. 귀하의 상황에 가장 적합한 것이 무엇인지 파악하는 것은 대부분 귀하에게 달려 있습니다.

이것이 반드시 가장 기술적 인 설명은 아니지만 그것이 내 머릿속에서 이해되는 방식입니다.


9
좋은 대답, 다른 대답을 추가하고 싶습니다 .Semaphore는 실행되는 스레드 수를 제어하는 ​​데 사용됩니다. 고정 된 리소스 세트가 있습니다. 스레드가 동일한 것을 소유 할 때마다 리소스 수가 감소합니다. 세마포어 수가 0에 도달하면 다른 스레드가 리소스를 획득 할 수 없습니다. 스레드는 리소스를 소유 한 다른 스레드가 해제 될 때까지 차단됩니다. 요컨대, 주요 차이점은 한 번에 리소스를 획득 할 수있는 스레드 수입니다. 뮤텍스는 하나입니다. 세마포어 -의 DEFINED_COUNT (세마포어 수가 많은 등)
berkay

10
간단한 if 대신에 while 루프가있는 이유를 설명하기 위해 : spurios wakeup . 인용 이 위키 피 디아 기사 : ; "그 이유 중 하나는 가짜 웨이크입니다, 스레드는 어떤 쓰레드가 조건 변수 신호 없어도는 대기 상태에서 해제 될 수 있습니다"
Vladislavs Burakovs을

3
트윗 담아 가기 브로드 캐스트가 사용 가능한 리소스보다 더 많은 스레드를 깨우는 경우에도 유용하다고 생각합니다 (예 : 브로드 캐스트는 3 개의 스레드를 깨우지 만 대기열에 2 개의 항목 만 있음).
브렌트, 코드 작성

대기열이 가득 찰 때까지 답변을 찬성하겠습니다.;) 완벽한 답변. 이 코드는 세마포어를 파악하는 데 도움이 될 수 있습니다. csc.villanova.edu/~mdamian/threads/PC.htm
Mohamad-Jaafar NEHME

3
@VladislavsBurakovs 조금 명확히하기 위해, 방금 깨어 난 스레드에 대해 조건이 여전히 거짓 일 수있는 이유는 스레드가 조건을 확인할 기회를 갖기 전에 컨텍스트 전환이 있었기 때문입니다. 다시, 다른 예약 된 스레드가 해당 조건을 거짓으로 만들었습니다. 이것이 내가 가짜 깨우기에 대해 아는 이유 중 하나입니다. 더 많은 것이 있는지 모르겠습니다.
Max

52

내부에 무엇이 있는지 밝혀 봅시다.

조건부 변수는 기본적으로 블로킹 대기 및 웨이크 업 작업을 지원 하는 대기 대기열 입니다. 즉, 스레드를 대기 대기열에 넣고 상태를 BLOCK으로 설정하고 스레드를 가져와 상태를 READY로 설정할 수 있습니다.

조건부 변수를 사용하려면 두 가지 다른 요소가 필요합니다.

  • 조건 (일반적으로 플래그 또는 카운터를 확인하여 구현 됨)
  • 조건을 보호하는 뮤텍스

그러면 프로토콜은

  1. 뮤텍스 획득
  2. 상태 확인
  3. 조건이 참이면 뮤텍스 차단 및 해제, 그렇지 않으면 뮤텍스 해제

세마포어는 본질적으로 카운터 + 뮤텍스 + 대기 큐입니다. 그리고 외부 의존성없이 그대로 사용할 수 있습니다. 뮤텍스 또는 조건부 변수로 사용할 수 있습니다.

따라서 세마포어는 조건부 변수보다 더 정교한 구조로 취급 될 수있는 반면 후자는 더 가볍고 유연합니다.


mutex는 조건 변수로 볼 수 있으며, 조건은 유지 여부입니다.
宏杰李

18

세마포어는 변수에 대한 배타적 액세스를 구현하는 데 사용할 수 있지만 동기화에 사용됩니다. 반면 뮤텍스는 상호 배제와 엄격하게 관련된 의미를 가지고 있습니다. 리소스를 잠근 프로세스 만이 잠금을 해제 할 수 있습니다.

불행히도 뮤텍스와의 동기화를 구현할 수 없기 때문에 조건 변수가 있습니다. 또한 조건 변수를 사용하면 브로드 캐스트 잠금 해제를 사용하여 동일한 순간에 모든 대기 스레드를 잠금 해제 할 수 있습니다. 이것은 세마포어로 수행 할 수 없습니다.


9

세마포어 및 조건 변수는 매우 유사하며 대부분 동일한 목적으로 사용됩니다. 그러나 하나를 선호 할 수있는 사소한 차이가 있습니다. 예를 들어 장벽 동기화를 구현하려면 세마포어를 사용할 수 없지만 조건 변수가 이상적입니다.

배리어 동기화는 모든 스레드가 스레드 함수의 특정 부분에 도달 할 때까지 모든 스레드를 기다리도록하는 것입니다. 이는 처음에는 각 스레드가 해당 장벽에 도달 할 때 감소하는 총 스레드 값인 정적 변수를 사용하여 구현할 수 있습니다. 이것은 마지막 스레드가 도착할 때까지 각 스레드가 잠자기를 원한다는 것을 의미합니다. 세마포어는 정반대를 수행합니다! 세마포어를 사용하면 각 스레드가 계속 실행되고 마지막 스레드 (세마포어 값을 0으로 설정)가 휴면 상태가됩니다.

반면에 조건 변수는 이상적입니다. 각 스레드가 장벽에 도달하면 정적 카운터가 0인지 확인합니다. 그렇지 않은 경우 조건 변수 대기 기능을 사용하여 스레드를 절전 모드로 설정합니다. 마지막 스레드가 장벽에 도달하면 카운터 값이 0으로 감소하고이 마지막 스레드는 다른 모든 스레드를 깨우는 조건 변수 신호 함수를 호출합니다!


1

모니터 동기화에서 조건 변수를 파일링합니다. 저는 일반적으로 세마포어와 모니터를 두 가지 다른 동기화 스타일로 보았습니다. 본질적으로 보관되는 상태 데이터의 양과 코드를 모델링하는 방법 측면에서 둘 사이에는 차이가 있습니다.하지만 실제로는 하나만 해결할 수 있지만 다른 하나는 해결할 수없는 문제가 없습니다.

저는 모니터 형식으로 코딩하는 경향이 있습니다. 대부분의 언어에서 뮤텍스, 조건 변수 및 일부 지원 상태 변수로 작업합니다. 그러나 세마포어도 그 일을 할 것입니다.


2
"모니터 양식"이 무엇인지 설명했다면 더 나은 대답이 될 것입니다.
Steven Lu

0

다음은 mutexconditional variables에서 상속됩니다 semaphore.

  • 를 들어 mutex1, semaphore0, 1 : 사용이 상태
  • 대한 사용 카운터.condition variablessemaphore

그들은 통사론 적 설탕과 같습니다.


C ++ 표준 라이브러리에서 이들은 모두 교육구 객체이며, 모두 플랫폼 별 API를 사용하여 구현됩니다. 확실히 세마포어는 시그널링 된 횟수를 차단 해제하고, 조건 변수는 여러 번 시그널링 될 수 있지만 한 번만 차단 해제됩니다. 이것이 wair가 뮤텍스를 매개 변수로 취하는 이유입니다.
doron
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.