답변:
잠금은 상호 배제에 사용됩니다. 코드 조각이 원 자성인지 확인하려면 그 주위에 잠금 장치를 두십시오. 이론적으로 이진 세마포어를 사용하여이 작업을 수행 할 수 있지만 이는 특별한 경우입니다.
세마포어 및 조건 변수는 잠금에 의해 제공되는 상호 배제 위에 구축되며 공유 리소스에 대한 동기화 된 액세스를 제공하는 데 사용됩니다. 유사한 목적으로 사용할 수 있습니다.
조건 변수는 일반적으로 리소스를 사용할 수있을 때까지 기다리는 동안 바쁜 대기 (조건을 확인하는 동안 반복해서 반복)를 방지하는 데 사용됩니다. 예를 들어 큐가 비워 질 때까지 계속할 수없는 스레드 (또는 여러 스레드)가있는 경우 바쁜 대기 방식은 다음과 같은 작업을 수행하는 것입니다.
//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()
작업 내에 숨겨지는 경향이 있습니다 .
확실히 두 선택 사이에 겹치는 부분이 있습니다. 세마포어 또는 조건 변수 (또는 조건 변수 세트)가 모두 사용자의 목적에 부합 할 수있는 시나리오가 많이 있습니다. 세마포어와 조건 변수는 모두 상호 배제를 유지하는 데 사용하는 잠금 개체와 연결되어 있지만 스레드 실행 동기화를 위해 잠금 위에 추가 기능을 제공합니다. 귀하의 상황에 가장 적합한 것이 무엇인지 파악하는 것은 대부분 귀하에게 달려 있습니다.
이것이 반드시 가장 기술적 인 설명은 아니지만 그것이 내 머릿속에서 이해되는 방식입니다.
내부에 무엇이 있는지 밝혀 봅시다.
조건부 변수는 기본적으로 블로킹 대기 및 웨이크 업 작업을 지원 하는 대기 대기열 입니다. 즉, 스레드를 대기 대기열에 넣고 상태를 BLOCK으로 설정하고 스레드를 가져와 상태를 READY로 설정할 수 있습니다.
조건부 변수를 사용하려면 두 가지 다른 요소가 필요합니다.
그러면 프로토콜은
세마포어는 본질적으로 카운터 + 뮤텍스 + 대기 큐입니다. 그리고 외부 의존성없이 그대로 사용할 수 있습니다. 뮤텍스 또는 조건부 변수로 사용할 수 있습니다.
따라서 세마포어는 조건부 변수보다 더 정교한 구조로 취급 될 수있는 반면 후자는 더 가볍고 유연합니다.
세마포어 및 조건 변수는 매우 유사하며 대부분 동일한 목적으로 사용됩니다. 그러나 하나를 선호 할 수있는 사소한 차이가 있습니다. 예를 들어 장벽 동기화를 구현하려면 세마포어를 사용할 수 없지만 조건 변수가 이상적입니다.
배리어 동기화는 모든 스레드가 스레드 함수의 특정 부분에 도달 할 때까지 모든 스레드를 기다리도록하는 것입니다. 이는 처음에는 각 스레드가 해당 장벽에 도달 할 때 감소하는 총 스레드 값인 정적 변수를 사용하여 구현할 수 있습니다. 이것은 마지막 스레드가 도착할 때까지 각 스레드가 잠자기를 원한다는 것을 의미합니다. 세마포어는 정반대를 수행합니다! 세마포어를 사용하면 각 스레드가 계속 실행되고 마지막 스레드 (세마포어 값을 0으로 설정)가 휴면 상태가됩니다.
반면에 조건 변수는 이상적입니다. 각 스레드가 장벽에 도달하면 정적 카운터가 0인지 확인합니다. 그렇지 않은 경우 조건 변수 대기 기능을 사용하여 스레드를 절전 모드로 설정합니다. 마지막 스레드가 장벽에 도달하면 카운터 값이 0으로 감소하고이 마지막 스레드는 다른 모든 스레드를 깨우는 조건 변수 신호 함수를 호출합니다!
모니터 동기화에서 조건 변수를 파일링합니다. 저는 일반적으로 세마포어와 모니터를 두 가지 다른 동기화 스타일로 보았습니다. 본질적으로 보관되는 상태 데이터의 양과 코드를 모델링하는 방법 측면에서 둘 사이에는 차이가 있습니다.하지만 실제로는 하나만 해결할 수 있지만 다른 하나는 해결할 수없는 문제가 없습니다.
저는 모니터 형식으로 코딩하는 경향이 있습니다. 대부분의 언어에서 뮤텍스, 조건 변수 및 일부 지원 상태 변수로 작업합니다. 그러나 세마포어도 그 일을 할 것입니다.
다음은 mutex
과 conditional variables
에서 상속됩니다 semaphore
.
mutex
1, semaphore
0, 1 : 사용이 상태condition variables
semaphore
그들은 통사론 적 설탕과 같습니다.