waitforsingleobject
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds); 리턴값 WAIT_FAILED : 대기 동작이 실패했음 ,GetLastError을 통해 자세한 정보를 얻음 WAIT_OBJECT_0 : 커널 객체가 주어진 시간 간격 안에 시그널된 상태로 변함 WAIT_TIMEOUT : 커널 객체가 시그널되기 전에 주어진 시간 초과 간격이 모두 지났음 WAIT_ABANDONED_0 : 커널 객체가 뮤텍스를 사용했고, 뮤텍스를 소유한 스레드가 자발적으로 뮤텍스의 소유권을 하제하지 않고 종료 //WaitForMultipleObjects 함수의 성공여부를 안전하게 검사하는 방법.., #define NUM_OBJECT 2 DWORD dwWaitResult; HANDLE hObjects[NUM_OBJECT]; int _tmain(int argc, _TCHAR* argv[]) { dwWaitResult = WaitForMultipleObjects(NUM_OBJECT, hObjects, FALSE, INFINITE); //리턴한 이유를 판단한다. if( (dwWaitResult >= WAIT_OBJECT_0)&& (dwWaitResult <= WAIT_OBJECT_0 + NUM_OBJECT -1) ) { //리턴값이 객체 중 하나가 시그널된 것을 나타내는 범위에 있는 경우이다. //이제 이 객체가 스레드 종료 이벤트인지 자원 뮤텍스인지를 판단하자 switch( dwWaitResult - WAIT_OBJECT_0) { case 0: // hThreadExitEvent에 의해 참조되는 이벤트가 시그널 되었다. // 이 스레드를 종료할 필요가 있는 경우 break; case 1: // hResourceMutex에 의해 참조되는 뮤텍스가 이 스레드에 의해서 // 소유 되었고 , 이 스레드가 새로운 작업을 할수 있게되는 경우 } } else { //대기 작업이 실패한 경우를 처리한다. // 필요에 따라 실패한 이유가 일반적인 실패(WAIT)FAILED),대기 시간 초과(WAIT_TIMEOUT),뮤텍스 포기(WAIT_ABANDONED_0)인지 분석 } return 0; } //리턴값 해석을 위한 INLINE 함수 inline BOOL WaitSucceeded( DWORD dwWaitResult, DWORD dwHandleCount) { //대기 동작이 성공하면 TRUE를 리턴하고 실패하면 FALSE를 리턴한다. return BOOL( (dwWaitResult >= WAIT_OBJECT_0)&& (dwWaitResult <= WAIT_OBJECT_0 + dwHandleCount -1) ); } inline BOOL WaitAbandoned( DWORD dwWaitResult , DWORD dwHandleCount ) { // 객체 중 하나가 포기된 뮤텍스이면 TRUE를, 아니면 FALSE return BOOL( (dwWaitResult >= WAIT_ABANDONED_0) && (dwWaitResult <= WAIT_ABANDONED_0 + dwHandleCount-1) ); } inline BOOL WaitTimeOut( DWORD dwWaitResult ) { // 대기 동작이 시간 초과이면 TRUE,아니면 FALSE return BOOL(WAIT_TIMEOUT == dwWaitResult); } inline BOOL WaitFailed( DWORD dwWaitResult ) { // 대기 동작이 실패하면 TRUE를 리턴하고, 아니면 FALSE를 리턴한다. // 이 함수가 TRUE를 리턴할 경우에는 GetLastError() 함수를 호출해서 // 실패한 이유에 대한 자세한 정보를 얻을 수 있다. return BOOL(WAIT_FAILED == dwWaitResult); } inline DWORD WaitSuccessIndex( DWORD dwWaitResult) { // 포기된 객체의 0 기준 (0-based) 인덱스를 리턴한다. // 이 함수는 WaitSucceeded() 함수가 TRUE를 리턴할 경우에만 호출되어야 한다. return(dwWaitResult - WAIT_OBJECT_0); } inline DWORD WaitAbandonedIndex( DWORD dwWaitResult ) { // 포기된 객체의 0 기준 (0-based) 인덱스를 리턴한다. // 이 함수는 WaitAbandoned() 함수가 TRUE를 리턴한 경우에만 // 호출되어야 한다. 리턴된 인덱스가 N번째 객체를 가리킨다고 해서 // 이것이 N번째 뮤텍스를 가리키는 것은 아니다. return(dwWaitResult - WAIT_ABANDONED_0); } 리턴값을 분석하는 것도 중요하지만, WaitForMultipleObject함수에 객체 핸들의 배열을 넘겨 줄때 핸들의 순서를 어떻게 할지 잘 생각해야한다. 만약 객체 중 어떤 하나라도 시그널되기를 대기하고 있다면(bWaitAll이 FALSE) 시그널 된 객체 중 가장 낮은 인덱스 값의 객체가 선택되고, 그 객체 핸들의 인덱스 값이 리턴된다. 예를 들어 위의 코드를 뮤텍스 핸들이 hObjects에서 인덱스 0이 되도록 재배치하고 스레드 종료 이벤트 객체를 인덱스 1로 했다면, 스레드 종료 이벤트가 오랫동안 시글널된 상태로 있는것을 확인 할수가 없다. 이런 상황은 대기 동작을 할 때마다 뮤텍스가 사용 가능해도 발생 할수 있다. 주 스레드는 이 일군 스레드가 스레드 종료 이벤트를 시그널링하도록 지정 했더라 도 WaitforMultipleObjects를 호출 했을때 뮤텍스가 더이 상 시그널된 상태가 아닐때까지 일꾼 스레드는 얼마동안 자신이 하던일을 계속해서 진행할수 있다. (무한히 진행할수도 있다.) 단지 일꾼 스레드는 스레드 종료 이벤트가 시그널 된 것을 발견하게 될 뿐이다. 대 부분의 경우에는 단순히 핸들을 "높은우선순위" 의 이벤트 객체로(위의 스레드 종료 이벤트와 같이) 만들거나 핸들 배열의 앞쭉에 가까운 예외 조건에서만 시그널되는 객체로 만드는 것만으로 충분하다.)