달력

52024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

10004, "블럭킹 윈속이 WSACancelBlockingCall 함수에서 취소되었습니다 ") );
10009, "잘못된 기술자(소켓 핸들)이다 ") );
10013, "브로드캐스트 어드레스를 위한 데이터그램 소켓의 접속시도가 setsockopt 함수로 SO_BROADCAST가 설정되어있지 않은 상태에서 실패 했습니다. ") );
10014, "name 또는 namelen 매개변수가 올바른 형태가 아닙니다. ") );
10022, "accept 하기 전에 listen 함수가 불려지지 않았습니다. ") );
10024, "새로운 소켓에 할당하기 위한 소켓 기술자가 더 이상 남아있지 않습니다 ") );
10035, "소켓 함수가 비블럭킹 모드로 동작중이다 ") );
10036, "블록화 함수가 호출 되는 동안 부적절한 소켓 함수가 호출되었다 ") );
10037, "이미 완료된 비동기 명령에 대한 취소가 시도됨 ") );
10038, "지정한 기술자가 소켓 기술자가 아닙니다 ") );
10039, "해당 함수에 목적지 어드레스가 필요하지만 제공되지 않았음 ") );
10040, "수신된 메시지가 지정된 버퍼에 저장하기에 너무 커서 손실 되었습니다 ") );
10041, "지정된 프로토콜이 잘못되었거나 이 소켓에 대해서 잘못된 형식입니다 ") );
10042, "알 수 없는 옵션이거나, 지원지지 않는 옵션을 사용했습니다. ") );
10043, "지정된 프로토콜이 지원되지 않는 형식입니다 ") );
10044, "지정된 소켓 타입이 지정한 어드레스 체계에서 지원되지 않는 형식입니다 ") );
10045, "socket이 연결지향형 서비스(SOCK_STREAM)형태가 아닙니다. ex) listen이 UDP socket에서 호출 ") );
10046, "지정된 프로토콜 체계가(PF_*) 지원되지 않습니다 ") );
10047, "지정된 어드레스 체계가(AF_*) 지원되지 않습니다 ") );
10048, "지정한 어드레스(IP)가 이미 사용중이다 ") );
10049, "지정된 어드레스는 로컬 머신에서 사용할 수가 없다 ") );
10050, "네트웍 서브 시스템에 에러가 발생했습니다 ") );
10051, "원격 시스템까지 네트웍이 도달할 수 없습니다 ") );
10052, "연산이 진행되고 있는 도중 접속이 끊겨버렸습니다. ") );
10053, "연결이 out-of-band나 다른 실패 때문에 끊어져 버렸습니다. ") );
10054, "원격 연결지에서 "hard"나 "abortive" 종료를 수행해서 리셋되었습니다. ") );
10055, "윈도우 소켓 시스템의 버퍼 공간이 모자라거나, 애플리케이션에 의해 API에게 제공된 공간이 너무 작아서 요청된 정보를 저장 할 수가 없음 ") );
10056, "지정된 소켓이 이미 연결 되어 있음 ") );
10057, "지정된 소켓이 이미 연결 되어 있지 않음 ") );
10058, "소켓이 셧다운(shutdown()) 되었습니다. ") );
10059, "지정한 함수에 대한 인자가 너무 많음") ); 
10060, "접속 시도가 시간초과 되었습니다. ") );
10061, "접속시도가 강제로 종료되었습니다 ") );
10062, "") );                  
10063, "") );                  
10064, "원격 호스트가 다운 되었음 ") );
10065, "네트웍 시스템 장애 등에 의해서 원격호스트까지도 달 할 수 없습니다.") );
10091, "네트워크 서브 시스템이 아직 통신할 준비가 되어 있지 않음(WSAStartup()이 반환)") ); 
10092, "요청한 윈도우즈 소켓 버전이 현재 윈도우즈 소켓 시스템에서 지원하지 않습니다. ") );
10093, "이 함수를 사용하기 전에 성공적인 WSAStartup 함수의 호출이 없었습니다.") ); 
11001, "호스트를 찾아낼 수 없습니다.") );
11002, "요청된 정보가 발견 되지 않음") );
11003, "회복할 수 없는 에러발생") );
11004, "잘못된 이름(name)으로 아무런 데이터가 기록되지 않았습니다. ") );
Posted by 위너즈
|

Thread 의 종료를 기다리기 WaitForSingleObject 를 사용할때 주의할 사항이 있다.

 

[main]

SetEvent(exit_event);
DWORD waitResult;
waitResult = WaitForSingleObject(m_loadingThread, 20000);

[m_loadingThread]

while(true) {

    waitResult = WaitForSingleObject(exit_event, 20000);

    if (waitResult == WAIT_OBJECT_0) break;

    // Some Task that takes some time.

}

위의 코드를 보자. m_loadingThread 에는 exit_event 를 주면 Thread 가 종료되는 코드가 루프로 돌고 있고, main 에서는 exit_event 를 세팅하여 Thread 를 종료시키고자 한다. 하지만, 이 경우 문제점이 있다.

Thread 가 "Some Task" 를 실행중인 경우라면 WaitForSingleObject 문이 실행되는 시점에 Thread 가 살아있고, Thread 가 루프를 다시 돌아 break 를 만나 쓰레드가 종료되면 해피한 케이스로 모든 일이 종료될 것이다.

하지만, SetEvent 와 동시에 break 를 만난다면? SetEvent 와 동시에 쓰레드 루프에서 벗어나 쓰레드 함수가 종료될 것이고, WaitForSingleObject 는 이미 종료되어 버린 Thread 의 handle 을 무작정 기다리게 된다.

 

MSDN 에서는 "어떤 현상이 발생할지 알 수 없다." 고 경고하고 있다. (빨간색 부분)

(http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx)

 

The WaitForSingleObject function returns when the specified object is in the signaled state or the time-out interval elapses.

To enter an alertable wait state, use the WaitForSingleObjectEx function. To wait for multiple objects, use the WaitForMultipleObjects.

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD dwMilliseconds
);

Parameters

hHandle
[in] Handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.

If this handle is closed while the wait is still pending, the function's behavior is undefined.

The handle must have the SYNCHRONIZE access right. For more information, see Standard Access Rights.

dwMilliseconds
[in] Time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If dwMilliseconds is zero, the function tests the object's state and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

실제 테스트 결과, 대체로 Hangup 이 걸리는 현상이 발생하였다.

사용시 Thread 가 종료된 상태로 WaitForSingleObject 를 만나는 일이 없도록 주의해야 한다.

 

Thread 종료시 Sleep 을 이용하는 방법도 있겠지만 Sleep 을 쓰는 방법은 가급적 지양하는 것이 좋을 것이므로

그래서 아래와 같이 로직을 보완하였다. thread_state 를 두어 Thread가 종료되었는지 체크하도록 한다.

 

[main]

SetEvent(exit_event);
DWORD waitResult;

if (thread_state != MY_STATE_EXIT)
     waitResult = WaitForSingleObject(m_loadingThread, 20000);

[m_loadingThread]

thread_state = MY_STATE_RUNNING;

while(true) {

    waitResult = WaitForSingleObject(exit_event, 20000);

    if (waitResult == WAIT_OBJECT_0) break;

    // Some Task that takes some time.

}

thread_state = MY_STATE_EXIT


출처 : http://blog.naver.com/hankawiii?Redirect=Log&logNo=90084211565
Posted by 위너즈
|

동기화를 위한 커널 객체의 특징

 • 커널 객체를 사용한 동기화의 경우 Signaled와 Nonsignaled의 두 가지 상태 중 하나로 존재하며, 동기화 객체가
   Signaled될 때까지 이 커널 객체를 사용하려는 스레드는 대기하고 있게 된다.

 • 프로세스를 생성하면 그 프로세스 내에 존재하는 커널 동기화 객체는 Nonsignaled 상태로 있게 되고,
   WaitForSingleObject()를 사용하여 이 커널 객체가 Signaled 될 때까지 기다릴 수 있으며, 프로세스 내에 존재하는
   커널 객체가 Signaled되는 시저은 그 프로세스가 종료하는 시점이 된다.
 • 유저 어플리케이션에서 모든 커널 객체가 핸들을 통하여 액세스되듯이 동기화를 위한 커널 객체 또한 핸들을
   사용하여 엑세스하게 된다. 그리고 이들 동기화 객체들은 모두 WaitForSingleObject() 또는
   WaitForMultipleObject()를 사용하여 그 객체가 Signaled될 때까지 기다릴 수 있게 된다.

출처 : Windows 구조와 원리 그리고 Codes

Posted by 위너즈
|

1. 크리티컬 섹션(Critical Section)이란?

 - 유저레벨 어플리케이션 작성 시 가장 간단하게 상요할 수 있는 방법이다.

 - 유저레벨의 동기화 방법 중 유일하게 커널 객체를사용하지 않으며 그 내부 구조가 단순하기 때문에
   동기화 처리를 하는 데 있어서 속도가 빠르다는 장점이 있으며 동일한 프로세스내에서만 사용할 수 있다는 제약이
   있다.

 - 크리티컬 섹션은 커널 객체를 사용하지 않기 때문에 핸들을 사용하지 않고 대신 CRITICAL_SECTION라는 타입을
   정의하여 사용하게 되며, 아래 4가지 Win32 API를 사용하여 동기화를 수행하게 된다.

     ◦VOID InitializeCriticalSection(LRCRITICAL_SECTION IpCriticalSection);
     ◦VOID DeleteCriticalSection(LRCRITICAL_SECTION IpCriticalSection);
     ◦VOID EnterCriticalSection(LRCRITICAL_SECTION IpCriticalSection);
     ◦VOID LeaveCriticalSection(LRCRITICAL_SECTION IpCriticalSection);
   ※ 커널 객체를 사용하지 않는 동기화 객체는 크리티컬 섹션뿐이며 뮤택스를 포함한 동기화 객체들,
      스레드(Thread), 파일(File)들까지도 동기화를 위한 커널 객체를 포함하고 있다.
      http://winnerz.tistory.com/

2. 뮤텍스(Mutex)란?

 - 뮤텍스는 최초에 Signaled 상태로 생성되어지며, WaitForSingleObject()와 같은 대기 함수를 호출함으로써
   NonSignaled 상태가 된다. WaitForSingleObject()와 같은 대기 함수에 대한 최초의 스레드 접근은 그 상태가
   Signaled이므로 스레드가 대기없이 해당 코드 영역으로 진입하게 되며, 이 진입이 일어난 후에는 뮤텍스의 상태가
   NonSignaled로 되므로 이후에 접근하는 스레드들은 대기하게 된다. 그리고 이후에 뮤텍스를 원래의 Signaled
   상태로 바꾸어 주는 ReleaseMutex() 함수를 사용함으로써 대기하고 있던 스레드가 다시 실행하게 되는 것이다.

 - 뮤텍스는 스레드가 여러 개 있더라도 자신이 소유한 스레드가 누구인지를 기억하고 있으며, Windows 운영체제는
   뮤텍스가 반환되지 않은 상태에서 스레드가 종료될 경우 그 뮤텍스를 강제적으로 Signaled 해줌으로써 이를
   대기하고 있던 스레드가 무한정 기다리는 일이 없도록 해준다.

 - 뮤텍스는 뮤텍스를 소유한 스레드를 기억하고 있음으로써 같은 스레드가 같은 뮤텍스를 중복 호출하더라도 데드락
   현상이 발생하기 않게 하고있다. 즉, 내부적으로 같은 스레드가 같은 뮤텍스를 소유하려 할 경우 뮤텍스의 내부적인
   카운트만을 증가시켜 주고 이 스레드에 대한 진입은 허용하여 주게 된다. 그리고 이 내부적인 카운트가 0으로
   내려갔을 경우에 Signaled 상태로 돌려줌으로써 다른 스레드에 대해서는 중복 호출한 스레드가 뮤텍스에 대한
   사용을 모두 종료한 후에 진입하도록 하고 있으며, 이러한 기능은 같은 스레드의 재귀 호출에 의한 데드락 현상을
   방지하여 주게 된다.


3. 이벤트(Event)란?

 - 이벤트는 어떠한 사건에 대하여 알리기 위한 용도로 사용되는 동기화 객체이다. 이벤트 객체의 경우 우리가
   Windows에서 메시지를 교환할 때 사용하는 개념과 같은 개념이다. 즉, Windows의 메시지 교환 방식은 이벤트에
   기반한 방식이라고 이야기한다. 키보드가 눌려질 경우 WM_KEYDOWN, 마우스 왼쪽 버튼이 눌러질 경우
   WM_LBUTTONDOWN과 같은 메시지가 날라오며, 이러한 신호는 이벤트를 통하여 통보하게 되는 것이다.

 - 이벤트의 경우 SetEvent() 또는 ResetEvent()를 사용하여 동기화 객체들의 상태를 마음대로 바꿀 수 있게 된다. 


4. 세마포어(Semaphore)란?

 - 세마포어는 사용자가 지정한 개수만큼 이 동기화 객체로 보호하는 자원에 대하여 접근할 수 있도록 하고 있다.
   즉, 세마포어에서는 사용 가능한 자원의 개수를 세팅할 수 있도록 하고 있으며, 그 값은 세마포어 초기화 시에
   세팅하게 된다.

 - 세마포어가 초기화되었을 때에는 뮤텍스와 마찬가지로 Signaled 상태로 되어 있으며, 세마포어의 자원이 하나
   사용될 때마다 사용 가능한 자원의 개수는 1씩 감소하게 된다. 그리고 이 개수 값이 1 이상일 때까지는 Signaled
   상태로 계속 유지되고 이 값이 0이 되면 세마포어의 상태는 NonSignaled가 되어 이 이후에 접근하는 스레드들에
   대하여 대기하도록 만들게 된다. 그리고 사용 가능한 자원의 개수가 다시 1 이상이 되면 세마포어의 상태가 다시
   Signaled 상태로 되어 대기하고 있던 스레드가 계속하여 세마포어의 자원을 사용할 수 있게 하는 것이다.

 - 세마포어의 자원에 대한 반환은 ReleaseSemaphore() 함수를 사용하며, 자신이 사용한 자원의 개수에 대하여
   lReleaseCount만큼 그 내부 카운터를 증가시키게 된다.

출처 : Windows 구조와 원리 그리고 Codes

Posted by 위너즈
|