http://hyurichel.tistory.com/entry/InitializeCriticalSectionAndSpinCount





InitializeCriticalSectionAndSpinCount

TCP / IP NetWork 2008/01/10 09:52
InitializeCriticalSectionAndSpinCount에 대해서 살짝 정리.
어제 정리했다시피 EnterCriticalSection 에서는 시스템 메모리가 부족할 때 오류가 발생합니다. 이것을 처리해 주기 위해서 throw-catch를 이용하거나 InitializeCriticalSectionAndSpinCount로 초기화 하는 방법을 제시 했었습니다.

그렇다면 InitializeCriticalSectionAndSpinCount이 뭐냐!!?
msdn을 뒤져보니까 

BOOL InitializeCriticalSectionAndSpinCount(
  LPCRITICAL_SECTION lpCriticalSection,  DWORD dwSpinCount);

Return. 성공하면 0이 아닌 값.
실패하면 0이 나옴. GetLastError로 에러를 살펴보면 되겠습니다.


이렇게 생겼습니다. 리턴값도 있고 기존의 것과 다른 인자가 하나 더 들어가는군요. 바로 dwSpinCount. Spin을 할 횟수를 지정하면 됩니다.

dwSpinCount는 싱글코어일 경우에 인자가 무시됩니다.(자동으로 0으로 셋팅됩니다)

멀티코어일 경우, 만약 Critical Section이 이용되지 않으면, Critical Section과 함께 세마포어 연합(?) 의 기다리는 동작이 Thread Spin을 부를 때 dwSpinCount만큼 부르게 됩니다.
만약 Spin동작에서 CriticalSection이 무효화 된다면 부르게 되는 Thread는 기다리는 동작을 피하게 됩니다.

...이게 뭔소리냐-_- 직독직해를 해버리니까 이따위로 나오는군요. 대충 의미를 되세겨 봅시다. 

Spin은 Wait 상태로 들어가기 전에 함수의 인자로 주어진 dwSpinCount만큼 루프를 돈다는 의미입니다. 루프 도는 중간에 Critical Section을 획득할 수 있다면 Thread를 교체하는 (Thread Context Switch)가 발생하지 않고 임계영역안에 접근 가능하다는 의미. 검색을 해보니까 dwSpinCount를 2000정도로 주는 것이 좋다고 합니다.


예를 들어보자면 1번 쿼리와 2번 쿼리가 있다고 했을 때 2번 쿼리에서 어는 특정 테이블을 변경하고 있다고 해 봅시다. 그런데 1번 쿼리에서 2번 쿼리가 변경하고 있는 테이블 값에 접근을 하려고 하는 경우 Critical Section에 의해서 접근이 불가됩니다. 이 때 일반적인 CriticalSection이라면 대기상태로 돌입하게 되는데, SpinCount가 지정되어 있다면 2번이 빠리 끝나기를 바라며 dwSpinCount만큼 재접근을 하는 겁니다. 그리고 실패해버리면 기다리는 모드로 들어가게 되고 성공하면 접근하는 것입니다.

이렇게 되면 싱글코어에서는 별 의미없겠지만 다중 프로세서일 경우에는 많은 의미가 생기겠지요? Thread의 ContextSwitch에 부하가 있는 데 그것을 피할 수 있을 가능성이 높아지겠지요. 기다리는 모드로 돌입하기 전에 접근 가능하는 경우가 꽤 많을 테니까요. 이상.





아래 링크는 위 글을 좀 더 간략하게 정리한 내용





http://blog.daum.net/jangun95/37


InitializeCriticalSectionAndSpinCount 함수

 

EnterCriticalSection 에서는 시스템 메모리가 부족할 때 오류가 발생합니다.

이것을 처리해 주기 위해서 try-catch를 이용해 예외처리를 하거나, InitializeCriticalSection 함수 대신 InitializeCriticalSectionAndSpinCount 함수를 이용합니다.

 

BOOL InitializeCriticalSectionAndSpinCount(
  LPCRITICAL_SECTION lpCriticalSection,  DWORD dwSpinCount);

InitializeCriticalSection 함수와 비교해보면 dwSpinCount라는 인자가 하나 더 추가되어 있습니다.

 

Spin은 Wait 상태로 들어가기 전에 함수의 인자로 주어진 dwSpinCount만큼 루프를 돈다는 의미입니다.

루프 도는 중간에 Critical Section을 획득할 수 있다면 Thread를 교체하는 Thread Context Switch가 발생하지 않고 임계영역안에 접근 가능하다는 말입니다.

 

dwSpinCount는 2000정도로 주는 것이 좋다고 합니다.

 

마지막으로 InitializeCriticalSectionAndSpinCount 함수를 사용하고 컴파일 시 오류가 발생한다면

StdAfx.h 에 _WIN32_WINNT 선언부를 다음과 같이 수정해 주십시오.

 

#define _WIN32_WINNT 0x0501  --> 윈도우 버전이 XP 이상일 경우를 말합니다.

 

[자료출처 : http://hyurichel.tistory.com]





http://bombfox.tistory.com/12



critical section을 위해 critical section object을 초기화 하고 겉돌기 횟수(spin count)를 설정한다.  스레드가 락이 걸린 critical section을 얻기 위해 시도했을 때, 스레드는 겉돈다(spin) : 그 것은 루프를 들어간다. 그 루프는 겉돌기 횟수만큼 반복하여 락이 해제됬는지를 보면서 검사한다. 만약 루프가 끝날 때까지 락이 해제가 되지 않았다면, 그 스레드는 락이 해제될 때 까지 sleep 상태에로 전이된다.

 

Critical Section Objects 사용 예

   1: // Global variable
   2: CRITICAL_SECTION CriticalSection; 
   3:  
   4: int main( void )
   5: {
   6:     ...
   7:  
   8:     // Initialize the critical section one time only.
   9:     if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 
  10:         0x00000400) ) 
  11:         return;
  12:     ...
  13:  
  14:     // Release resources used by the critical section object.
  15:     DeleteCriticalSection(&CriticalSection);
  16: }
  17:  
  18: DWORD WINAPI ThreadProc( LPVOID lpParameter )
  19: {
  20:     ...
  21:  
  22:     // Request ownership of the critical section.
  23:     EnterCriticalSection(&CriticalSection); 
  24:  
  25:     // Access the shared resource.
  26:  
  27:     // Release ownership of the critical section.
  28:     LeaveCriticalSection(&CriticalSection);
  29:  
  30:     ...
  31: return 1;
  32: }


원문 : http://msdn.microsoft.com/en-us/library/ms683476(v=vs.85).aspx 

 Gems7권의 고성능 힙 관리자 예제가 컴파일이 안되는데 원인은 InitializeCriticalSectionAndSpinCount() 이 정의되있지 않다는 것이다.

   1: #ifndef _HPHA_H_
   2: #define _HPHA_H_
   3:  
   4: #include <memory.h>
   5: #include <string.h>
   6: #include <assert.h>
   7: #include <new>
   8:  
   9:  
  10: #if defined(WIN32)
  11:  
  12: #define _WIN32_WINNT 0x0501 // 추가해줌
  13:  
  14: #ifndef WIN32_LEAN_AND_MEAN
  15: #define WIN32_LEAN_AND_MEAN
  16: #endif
  17: #ifndef _WIN32_WINNT
  18: #define _WIN32_WINNT WINVER
  19: #endif
  20: #include <windows.h>
  21: #else
  22: #error "Platform undefined or not supported"
  23: #endif


winbase.h 에 InitializeCriticalSectionAndSpinCount()는 다음과 같이 선언되있다. 

   1: // winbase.h
   2: #if (_WIN32_WINNT >= 0x0403)  
   3:  
   4: WINBASEAPI  
   5:  
   6: BOOL 
   7:  
   8: WINAPI  
   9:  
  10: InitializeCriticalSectionAndSpinCount(  
  11:  
  12:     __out LPCRITICAL_SECTION lpCriticalSection,  
  13:  
  14:     __in  DWORD dwSpinCount  
  15:  
  16:     ); 

  17:  




BLOG main image


아래 포스트는 크리티컬섹션에 대한 간단한 클래스인데

InitializeCriticalSection 을 InitializeCriticalSectionAndSpinCount 으로 변경해줘야 memory oiut 에러가 나지 않음, 아래는 퍼온글






http://codemuri.tistory.com/20



크리티컬 섹션 초간단 클래스


class CCriticalSection

{

public:

    void Lock() { EnterCriticalSection(&m_sec); }

    void Unlock() { LeaveCriticalSection(&m_sec); }

    CCriticalSection() { InitializeCriticalSection(&m_sec); } 

    ~CCriticalSection() { DeleteCriticalSection(&m_sec); }

    CRITICAL_SECTION m_sec;

};



출처가 MSDN이라 그냥 써도 될듯함. 


From MSDN :



반응형

+ Recent posts