동기는
멀티스레드(프로세스) 프로그래밍 모델을 접하면서 시작되었고, 배운 것은 세마포어(Semaphore)와 관련된 동기화 프리미티브였습니다. .Net Framework에 해당 항목이 없는 이유를 모르겠습니다. 끔찍한 것은 혁명의 순교자들이 약을 먹고 헛되이 피를 흘리는 것을 막기 위해 그녀를 사용하여 오랜 시간 테스트를 거친 많은 C++ 코드를 구현했다는 것입니다.
세마포어란 무엇입니까?
이미 세마포어의 개념을 이해하고 있다면 이 섹션을 건너뛰시기 바랍니다.
세마포어는 다중 스레드 환경에서 사용되는 기능으로, 공용 리소스를 올바르고 합리적으로 사용할 수 있도록 다양한 스레드를 조정하는 역할을 합니다.
주차장이 어떻게 작동하는지 살펴 보겠습니다. 단순화를 위해 주차장에 주차 공간이 3개만 있고 처음에는 3개의 주차 공간이 모두 비어 있다고 가정합니다. 이는 5대의 차량이 동시에 오고, 문지기가 3대의 차량을 방해 없이 진입하도록 허용한 후 차량 블록을 내려놓으면, 나머지 차량은 입구에서 대기해야 하고, 다음 차량도 입구에서 대기해야 합니다. 입구. 이때 주차장에서 차가 한 대 빠져나갔는데, 문지기가 이를 알고 차문을 열고 차 한 대를 넣었다. 두 대가 더 남으면 두 대를 더 넣을 수 있다는 식이었다.
이 주차장 시스템에서 주차 공간은 공공 자원이고, 각 차량은 스레드와 같으며, 게이트키퍼는 세마포어 역할을 합니다.
또한, 세마포어의 특징은 다음과 같습니다. 세마포어는 음이 아닌 정수(주차장 수)이며, 이를 전달하는 모든 스레드(차량)는 정수를 1씩 감소시킵니다(전달하는 것은 물론 자원을 사용하는 것입니다) ) 정수 값이 0이면 이를 전달하려는 모든 스레드가 대기 상태가 됩니다. 우리는 세마포어에 대해 대기(Wait)와 해제(Release)라는 두 가지 작업을 정의합니다. 스레드가 대기 작업을 호출하면 세마포어를 전달한 다음 1씩 감소시키거나 세마포어가 1보다 크거나 시간 초과될 때까지 기다립니다. Release는 실제로 주차장을 떠나는 차량에 해당하는 세마포어에 대한 추가 작업을 수행합니다. 이 작업을 "릴리스"라고 부르는 이유는 추가 작업이 실제로 세마포어에 의해 보호되는 리소스를 해제하기 때문입니다.
성취하다
우리 모두 알고 있듯이 .Net Framework 클래스 라이브러리에서 제공되는 스레드 동기화 기능에는
Monitor, AutoResetEvent, ManualResetEvent, Mutex, ReadWriteLock 및 InterLock이 포함됩니다. 그 중 AutoResetEvent, ManualResetEvent, Mutex는 WaitHandler에서 파생되며 실제로 운영 체제에서 제공하는 커널 개체를 캡슐화합니다. 다른 것들은 .Net 가상 머신에 기본적으로 있어야 합니다. 분명히 운영 체제 커널 개체의 기능은 사용하기에 덜 효율적입니다. 그러나 효율성은 여기서 고려해야 할 문제가 아닙니다. 두 개의 모니터와 ManualResetEvent 개체를 사용하여 세마포어를 시뮬레이션합니다.
코드는 다음과 같습니다:
공개 클래스 세마포어
{
개인 ManualResetEvent waitEvent = 새로운 ManualResetEvent(false);
개인 개체 syncObjWait = 새 개체();
private int maxCount = 1; //최대 리소스 수
private int currentCount = 0; //현재 리소스 수
public Semaphore()
{
}
공개 세마포( int maxCount )
{
this.maxCount = 최대카운트;
}
공개 bool 대기()
{
lock( syncObjWait ) //하나의 스레드만 다음 코드를 입력할 수 있습니다.
{
bool waitResult = this.waitEvent.WaitOne(); //여기에서 대기 중인 리소스 수가 0보다 큽니다.
if(대기결과)
{
자물쇠(이것)
{
if(현재 개수 > 0)
{
현재 개수--;
if(현재카운트 == 0)
{
this.waitEvent.Reset();
}
}
또 다른
{
System.Diagnostics.Debug.Assert( false, "세마포는 현재 개수 < 0을 허용하지 않습니다." );
}
}
}
waitResult를 반환합니다.
}
}
/**//// <요약>
/// 타임아웃 반환을 허용하는 대기 연산
/// </summary>
/// <param name="millisecondsTimeout"></param>
/// <반환></반환>
public bool Wait(int millisecondsTimeout)
{
lock( syncObjWait ) // 모니터는 범위 클래스 코드가 임계 섹션 내에 있는지 확인합니다.
{
bool waitResult = this.waitEvent.WaitOne(millisecondsTimeout,false);
if(대기결과)
{
자물쇠(이것)
{
if(현재 개수 > 0)
{
현재 개수--;
if(현재카운트 == 0)
{
this.waitEvent.Reset();
}
}
또 다른
{
System.Diagnostics.Debug.Assert( false, "세마포는 현재 개수 < 0을 허용하지 않습니다." );
}
}
}
waitResult를 반환합니다.
}
}
공개 bool 릴리스()
{
lock( this ) // 모니터는 범위 클래스 코드가 임계 섹션 내에 있는지 확인합니다.
{
현재카운트++;
if(현재카운트 > this.maxCount)
{
currentCount = this.maxCount;
거짓을 반환;
}
this.waitEvent.Set(); //Wait을 호출하는 스레드의 진입을 허용합니다.
}
사실을 반환;
}
}