Windows 스레드 동기화 임계점 객체(Critical Section)

우리도 임계 구역을 통해 같은 시간 내에 공유 데이터에 대한 제어 접근을 보장할 수 있다.임계 구역은 내부 핵 대상이 아니라 프로세스 내부의 라인만 동기화할 수 있다.
임계 영역 객체는 데이터 세그먼트에 정의된 CRITICAL 입니다.SECTION 구조는 Windows 내부에서 이 구조가 기록한 정보를 사용하여 같은 시간에 한 라인만 이 임계구에서 보호된 데이터에 접근할 수 있도록 합니다.
임계 영역 객체는 다음과 같이 호출할 함수 인터페이스를 사용합니다.

(1)InitializeCriticalSection()

void WINAPI InitializeCriticalSection(
  _Out_  LPCRITICAL_SECTION lpCriticalSection
);

//lpCriticalSection: 

CRITICAL 작성SECTION 객체 후에는 임계 영역 객체를 초기화하기 위해 함수를 호출해야 합니다.임계 영역에서 보호된 리소스에 액세스하기 전에 모든 스레드가 CRITICALSECTION 구조 객체의 내부 멤버가 초기화되어야 합니다.만약 루틴이 초기화되지 않은 CRITICAL 에 들어가려고 시도한다면SECTION, 그러면 결과는 예측할 수 없습니다.

(2)EnterCriticalSection()

void WINAPI EnterCriticalSection(
  _Inout_  LPCRITICAL_SECTION lpCriticalSection
);
//lpCriticalSection: 

루틴이 임계 구역에서 보호된 데이터에 접근할 때 이 함수를 임계 구역에 먼저 호출해야 한다. 같은 시간에 윈도는 한 개의 루틴만 임계 구역에 진입한다. 만약에 EnterCritical Section을 호출할 때 이미 루틴이 임계 구역에 있다면 이벤트 핵 대상을 호출하여 호출 루틴을 대기 상태로 전환시킨다. 이렇게 하면 호출 루틴은 어떠한 CPU 시간도 낭비하지 않는다.시스템 커널은 이 스레드가 액세스하려는 리소스를 기억합니다. 리소스를 사용할 수 있는 다른 스레드가 LeaveCriticalSection을 호출하면 대기 중인 스레드가 다시 스케줄링 가능한 상태로 전환됩니다.

(3)TryEnterCriticalSection()

BOOL WINAPI TryEnterCriticalSection(
  _Inout_  LPCRITICAL_SECTION lpCriticalSection
);

//lpCriticalSection: 
//Return Value: 

TryEnterCriticalSection과 EnterCriticalSection 함수의 유일한 차이점은 호출 스레드가 대기 상태에 들어가지 않는다는 것이다.만약 공유 자원이 정말 다른 루트에 접근한다면, 이 함수는 FALSE로 되돌아와 임계구역에 들어가는 데 실패한 것을 의미하고, TRUE로 되돌아가면 임계구역에 들어간 것을 의미한다.

(4)LeaveCriticalSection()

void WINAPI LeaveCriticalSection(
  _Inout_  LPCRITICAL_SECTION lpCriticalSection
);

//lpCriticalSection: 

스레드가 공유 자원에 대한 접근을 완료하면 다른 스레드가 접근할 수 있도록 이 함수를 임계 구역에서 호출해야 합니다.

(5)DeleteCriticalSection()

void WINAPI DeleteCriticalSection(
  _Inout_  LPCRITICAL_SECTION lpCriticalSection
);

//lpCriticalSection: 

프로그램이 임계 구역을 더 이상 사용하지 않을 때, 이 함수를 호출해서 임계 구역의 대상을 삭제해야 한다.
임계 영역 객체를 사용할 때는 다음 두 가지 사항을 고려해야 합니다.
  • 공유 자원에 접근하는 모든 코드는 EnterCritical Section과 LeaveCritical Section 사이에 두어야 한다. 즉, 이 두 함수가 쌍으로 나타나야 한다. 그렇지 않으면 공유 자원이 파괴될 수 있다.
  • 임계 구역 내에서 비교적 긴 시간을 운행하지 마라. 그러면 프로그램의 성능에 영향을 줄 수 있다.

  • 다음 절차에서는 임계 영역 기능을 테스트합니다.
    #include <iostream>
    #include <windows.h>
    #include <process.h>
    
    using namespace  std;
    
    CRITICAL_SECTION csTest;
    volatile int flag = 0;
    
    void CriticalSectionTest1(void *ptr)
    {
        EnterCriticalSection(&csTest);
    
        flag = 1;
        for (int i = 0; i < 5; ++i)
        {
            Sleep(1000);
            cout<<flag<<' ';
        }
    
        LeaveCriticalSection(&csTest);
    }
    
    void CriticalSectionTest2(void *ptr)
    {
        EnterCriticalSection(&csTest);
    
        flag = 2;
        for (int i = 0; i < 5; ++i)
        {
            Sleep(1000);
            cout<<flag<<' ';
        }
        LeaveCriticalSection(&csTest);
    }
    
    int main()
    {
        InitializeCriticalSection(&csTest);
    
        _beginthread(CriticalSectionTest1, 0, NULL);
        _beginthread(CriticalSectionTest2, 0, NULL);
        
        Sleep(INFINITE);
    
        DeleteCriticalSection(&csTest);
    }

    프로그램 실행 결과:
    2 2 2 2 2 1 1 1 1 1
    운행 결과에서 알 수 있듯이 두 라인이 서로 밀어내는 접근 임계구 자원은 임계구에 들어간 후에 Sleep 함수를 호출하는 것을 시험하기 위해 실제 프로그램에서 이러한 행위는 프로그램의 성능에 심각한 영향을 줄 수 있다.
    Jun 19, 2013 PM 22:58 @dorm

    좋은 웹페이지 즐겨찾기