SlideShare a Scribd company logo
1 of 27
구본탁
1. 대기 함수들
이 함수를 호출한 스레드가 어떻게 다시 스케줄이 가능하게
되었는지를 리턴함.
리턴값 설명
WAIT_OBJECT_0 스레드가 대기하던 오브젝트가 시그널 되었음.
WAIT_TIMEOUT 타임아웃 발생.
WAIT_FAILED 파라미터가 잘못 입력됨.
1. 대기 함수들
bWaitAll
▶ 함수의 동작 방식을 결정하는 매개변수
▶ TRUE -> 모든 오브젝트들이 시그널 상태가 될때 까지 스레드를 대기 상태로 둠, 반환
값은 WAIT_OBJECT_0가 반환됨
▶ FALSE -> 지정한 오브젝트 들 중 단 하나라도 시그널 상태가 되면 함수 반환, 반환 값은
WAIT_OBJECT_0 ~ bWaitAll-1 사이 숫자로 결정됨
2. 성공적인 대기의 부가적인 영향
• 성공적인 호출을 통해 오브젝트의 상태가 변경되는 것을 일컬어
‘성공적인 대기의 부가적인 영향’이라고 한다.
3. 이벤트 커널 오브젝트
3. 이벤트 커널 오브젝트
•다른 프로세스에서 수행되는 스레드의 경우 pszName매개변수로
전달하는 이름을 이용하거나, 상속, DuplicateHandle 함수 등을 사용하여
동일한 커널오브젝트에 접근할 수 있다.
•또는 OpenEvent 함수에 pszName매개변수에 지정한 이름을 매개변수로
전달하여 동일한 이벤트에 접근할 수 있다.
3. 이벤트 커널 오브젝트
3. 이벤트 커널 오브젝트
3. 이벤트 커널 오브젝트
핸드셰이크 예제 애플리케이션
•https://github.com/cggos/windows_via_cpp/tree/master/09-Handshake
4. 대기 타이머 커널 오브젝트
4. 대기 타이머 커널 오브젝트
대기 타이머를 이용하여 APC 요청을 스레드의 APC 큐에 삽입하는 방법
4. 대기 타이머 커널 오브젝트
4. 대기 타이머 커널 오브젝트
4. 대기 타이머 커널 오브젝트
타이머와 관련된 미결 문제
•타이머는 종종 통신 프로토콜을 구현하는데 사용되기도 한다. 이때, 매 요청별로 타이머 커널 오브젝트를 생성하게 되면 시스템의
성능이 저하될 수도 있기 때문에 가능하다면 하나의 타이머 오브젝트만을 생성하고, 시그널 시간을 적절히 변경해 가면서
재사용하는 것이 좋다.
•직접 타이머 시간을 변경하고 재설정하는 작업을 수행하는 대신 새롭게 추가된 스테드 풀링 함수의 하나인
CreateThreadpoolTimer와 같은 함수를 사용한다.
•윈도우 개발에 익숙한 개발자라면 대기 타이머와 유저타이머(SetTimer 함수를 사용하는)를 비교해 보려 할 것이다. 가장 큰
차이점은 유저 타이머의 경우 비교적 리소스를 많이 사용하는 사용자 인터페이스 환경 하에서만 수행된다는 것이다. 대기
타이머는 커널 오브젝트이기 때문에 다수의 스레드에 의해 공유될 수 있으며, 좀더 보안에 안정적이다.
5. 세마포어 커널 오브젝트
•세마포어 커널 오브젝트는 리소스의 개수를 고려해야 하는 상황에서 주로 사용된다.
•세마포어는 다음의 규칙에 따라 동작한다.
1. 현재 리소스 카운트가 0보다 크면 세마포어는 시그널 상태가 된다.
2. 현재 리소스 카운트가 0이면 세마포어는 논시그널 상태가 된다.
3. 시스템은 현재 리소스 카운트를 음수로 만들 수 없다.
4. 현재 리소스 카운트는 최대 리소스 카운트보다 커질 수 없다.
• 세마포어를 사용할 때에는 오브젝트의 사용 카운트와 현재 리소스 카운트를 혼돈하지 않도록 주의해야 한다.
5. 세마포어 커널 오브젝트
•세마포어 커널 오브젝트를 생성하려면 CreateSemaphore 함수를 사용하면 된다.
•현재는 아래와 같이 변경되었음.
5. 세마포어 커널 오브젝트
•CreateSemaphoreEx 함수를 이용하면 dwDesiredAccess 매개변수를 통해 세마포어에 대한 접근권한을 바로 지정할 수 있다
5. 세마포어 커널 오브젝트
•모든 프로세스는 OpenSemaphore 함수를 이용하여 이미 생성된 세마포어를 가리키는
프로세스 고유의 핸들값을 얻을 수 있다.
5. 세마포어 커널 오브젝트
•세마포어의 현재 리소스 카운트를 증가시키기 위해서는 ReleaseSemaphore 함수를
호출하면 된다.
6. 뮤텍스 커널 오브젝트
•뮤텍스 커널 오브젝트는 스레드가 단일의 리소스에 대해 배타적으로 접근할 수 있도록 해 준다. 사실 뮤텍스(MUTual
EXclusion)이라는 이름도 이러한 특성으로부터 기인한 것이다. 이 커널 오브젝트는 사용 카운트, 스레드ID, 반복 카운터를 저장할 수
있는 공간을 가지고 있다.
•뮤텍스의 동작 방식은 크리티컬 섹션과 동일하다. 하지만 크리티컬 섹션이 유저 모드 동기화 오브젝트인 데 반해 뮤텍스는 커널
오브젝트라는 차이점이 있다. 이러한 차이점 때문에 뮤텍스는 크리티컬 섹션에 비해 느리지만, 서로 다른 프로세스에서 동일 뮤텍스에
대해 접근이 가능하며, 리소스에 대한 접근 권한을 획득할 때 시간 제한을 지정할 수 있다는 장점이 있다.
•스레드 ID : 시스템 내의 어떤 스레드가 뮤텍스를 소유하고 있는지를 나타내는 값이다.
•반복 카운터 : 뮤텍스를 소유하고 있는 스레드가 몇 회나 반복적으로 뮤텍스를 소유하고자 했는지에 대한 횟수를 나타내는 값이다.
•뮤텍스는 다수의 스레드가 동시에 접근하는 메모리 블록을 보호하기 위해 사용되기도 한다.
•뮤텍스는 다음의 규칙에 따라 동작한다.
1. 스레드ID가 0(유효하지 않는 스레드ID)이면 뮤텍스는 어떠한 스레드에 의해서도 소유되지 않은 것이며, 이때 뮤텍스는 시그널
상태가 된다.
2. 스레드ID가 0이 아니면 뮤텍스는 특정 스레드에 의해 소유된 것이며, 이때 논시그널 상태가 된다.
3. 다른 커널 오브젝트와는 다르게 뮤텍스는 특수한 코드를 포함하고 있어서 일반적인 규칙을 위반하는 경우도 있다.
6. 뮤텍스 커널 오브젝트
•뮤텍스를 사용하려면 CreateMutex 함수를 호출해서 뮤텍스를 생성해야
한다.
• 아래 함수의 dwDesiredAccess 파라미터를 통해 뮤텍스에 대한 접근 권한을 바로 지정할 수 있다
• 모든 프로세스는 OpenMutex 함수를 이용하여 이미 생성된 뮤텍스를 가리키는 프로세스 고유의
핸들값을 얻을 수 있다.
6. 뮤텍스 커널 오브젝트
•리소스에 대한 접근 권한을 획득한 스레드가 더 이상 리소스를 사용할 필요가 없어지면
반드시 ReleaseMutex 함수를 호출하여 뮤텍스의 소유권을 해제해 주어야 한다
6. 뮤텍스 커널 오브젝트
① 버림 문제 (Abandonment issues)
•뮤텍스는 다른 모든 커널 오브젝트와는 다르게 "스레드 소유권(thread
ownership)"의 개념을 가지고 있다. 뮤텍스만이 어떤 스레드가 성공적인 대기를
수행하였는지를 기록해 둔다. 이러한 뮤텍스의 스레드 소유권이라는 개념 때문에
뮤텍스가 논 시그널 상태임에도 불구하고 스레드가 뮤텍스를 다시 소유할 수 있는
예외적인 규칙을 가지게 된 것이다.
•뮤텍스와 스레드 커널 오브젝트를 계속해서 추적하고 있기 때문에 언제 뮤텍스가
벼려졌는지(소유권을 해제하지 않고 스레드 종료) 정확히 알 수 있으며, 뮤텍스의
버림이 발생하면 버려진 뮤텍스의 스레드 ID와 반복 카운트를 0으로 변경한다. 이
경우 대기 함수는 WAIT_ABANDONED라는 특별한 값을 반환한다
6. 뮤텍스 커널 오브젝트
② 뮤텍스와 크리티컬 섹션
6. 뮤텍스 커널 오브젝트
•③ 큐 예제 애플리케이션
7. 편리한 스레드 동기화 오브젝트 표
감사합니다

More Related Content

What's hot

Game programming patterns 2
Game programming patterns 2Game programming patterns 2
Game programming patterns 2
QooJuice
 
UE4 Garbage Collection
UE4 Garbage CollectionUE4 Garbage Collection
UE4 Garbage Collection
QooJuice
 
[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스
종빈 오
 
리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션
QooJuice
 
스레드
스레드스레드
스레드
xxbdxx
 
07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도
ssuser3fb17c
 

What's hot (20)

120114 windows viacpp_03
120114 windows viacpp_03120114 windows viacpp_03
120114 windows viacpp_03
 
Multi thread
Multi threadMulti thread
Multi thread
 
Game programming patterns 2
Game programming patterns 2Game programming patterns 2
Game programming patterns 2
 
UE4 Garbage Collection
UE4 Garbage CollectionUE4 Garbage Collection
UE4 Garbage Collection
 
windows via c++ Ch 5. Job
windows via c++ Ch 5. Jobwindows via c++ Ch 5. Job
windows via c++ Ch 5. Job
 
Windows via c++ chapter6
Windows via c++   chapter6Windows via c++   chapter6
Windows via c++ chapter6
 
[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스[Windows via c/c++] 4장 프로세스
[Windows via c/c++] 4장 프로세스
 
리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션
 
Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object pooling
 
Lock free queue
Lock free queueLock free queue
Lock free queue
 
비동기 파일 로딩
비동기 파일 로딩비동기 파일 로딩
비동기 파일 로딩
 
multi-thread 어플리케이션에 대해 모든 개발자가 알아 두지 않으면 안 되는 것
multi-thread 어플리케이션에 대해 모든 개발자가 알아 두지 않으면 안 되는 것multi-thread 어플리케이션에 대해 모든 개발자가 알아 두지 않으면 안 되는 것
multi-thread 어플리케이션에 대해 모든 개발자가 알아 두지 않으면 안 되는 것
 
시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
 
tcp ip study
tcp ip studytcp ip study
tcp ip study
 
Concurrency in action - chapter 7
Concurrency in action - chapter 7Concurrency in action - chapter 7
Concurrency in action - chapter 7
 
Multi-thread : producer - consumer
Multi-thread : producer - consumerMulti-thread : producer - consumer
Multi-thread : producer - consumer
 
스레드
스레드스레드
스레드
 
Go lang(goroutine, channel, 동기화 객체)
Go lang(goroutine, channel, 동기화 객체)Go lang(goroutine, channel, 동기화 객체)
Go lang(goroutine, channel, 동기화 객체)
 
07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도
 
Concurrency in action - chapter 5
Concurrency in action - chapter 5Concurrency in action - chapter 5
Concurrency in action - chapter 5
 

Similar to Windows via c/c++ 스터디9장

도메인 객체의 생명주기
도메인 객체의 생명주기도메인 객체의 생명주기
도메인 객체의 생명주기
ukjinkwoun
 
동기화, 스케줄링
동기화, 스케줄링동기화, 스케줄링
동기화, 스케줄링
xxbdxx
 

Similar to Windows via c/c++ 스터디9장 (20)

[Solr 스터디] Solr 설정 및 색인 (2017)
[Solr 스터디] Solr 설정 및 색인 (2017)[Solr 스터디] Solr 설정 및 색인 (2017)
[Solr 스터디] Solr 설정 및 색인 (2017)
 
일래스틱 서치 ch7. 일래스틱 서치 클러스터 세부사항
일래스틱 서치 ch7. 일래스틱 서치 클러스터 세부사항일래스틱 서치 ch7. 일래스틱 서치 클러스터 세부사항
일래스틱 서치 ch7. 일래스틱 서치 클러스터 세부사항
 
JVM Synchronization_Wh apm
JVM Synchronization_Wh apmJVM Synchronization_Wh apm
JVM Synchronization_Wh apm
 
android_thread
android_threadandroid_thread
android_thread
 
[넥슨] kubernetes 소개 (2018)
[넥슨] kubernetes 소개 (2018)[넥슨] kubernetes 소개 (2018)
[넥슨] kubernetes 소개 (2018)
 
Gcd ppt
Gcd pptGcd ppt
Gcd ppt
 
도메인 객체의 생명주기
도메인 객체의 생명주기도메인 객체의 생명주기
도메인 객체의 생명주기
 
디자인패턴 1~13
디자인패턴 1~13디자인패턴 1~13
디자인패턴 1~13
 
Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준
 
Kubernetes
Kubernetes Kubernetes
Kubernetes
 
Mcollective orchestration tool 소개
Mcollective orchestration tool 소개Mcollective orchestration tool 소개
Mcollective orchestration tool 소개
 
Anatomy of Realm
Anatomy of RealmAnatomy of Realm
Anatomy of Realm
 
AWS Aurora 운영사례 (by 배은미)
AWS Aurora 운영사례 (by 배은미)AWS Aurora 운영사례 (by 배은미)
AWS Aurora 운영사례 (by 배은미)
 
동기화, 스케줄링
동기화, 스케줄링동기화, 스케줄링
동기화, 스케줄링
 
K8s in action chap15
K8s in action chap15K8s in action chap15
K8s in action chap15
 
Node.js 기본
Node.js 기본Node.js 기본
Node.js 기본
 
C++ Advanced 강의 4주차
 C++ Advanced 강의 4주차 C++ Advanced 강의 4주차
C++ Advanced 강의 4주차
 
Rx java essentials
Rx java essentialsRx java essentials
Rx java essentials
 
Zoo keeper 소개
Zoo keeper 소개Zoo keeper 소개
Zoo keeper 소개
 
쓰레드.pdf
쓰레드.pdf쓰레드.pdf
쓰레드.pdf
 

More from HolyTak (12)

14장 입자 시스템과 스트림 출력.pptx
14장 입자 시스템과 스트림 출력.pptx14장 입자 시스템과 스트림 출력.pptx
14장 입자 시스템과 스트림 출력.pptx
 
Graphics 14장 1인칭 카메라 만들기.pptx
Graphics 14장 1인칭 카메라 만들기.pptxGraphics 14장 1인칭 카메라 만들기.pptx
Graphics 14장 1인칭 카메라 만들기.pptx
 
Graphics 8장 텍스처 적용.pptx
Graphics 8장 텍스처 적용.pptxGraphics 8장 텍스처 적용.pptx
Graphics 8장 텍스처 적용.pptx
 
Graphics 2장 행렬.pptx
Graphics 2장 행렬.pptxGraphics 2장 행렬.pptx
Graphics 2장 행렬.pptx
 
Windosw via c 스터디26장.pptx
Windosw via c 스터디26장.pptxWindosw via c 스터디26장.pptx
Windosw via c 스터디26장.pptx
 
Windosw via c 스터디23장.pptx
Windosw via c 스터디23장.pptxWindosw via c 스터디23장.pptx
Windosw via c 스터디23장.pptx
 
Windosw via c 스터디23장.pptx
Windosw via c 스터디23장.pptxWindosw via c 스터디23장.pptx
Windosw via c 스터디23장.pptx
 
Windosw via c 스터디20장.pptx
Windosw via c 스터디20장.pptxWindosw via c 스터디20장.pptx
Windosw via c 스터디20장.pptx
 
Windosw via c 스터디17장
Windosw via c 스터디17장Windosw via c 스터디17장
Windosw via c 스터디17장
 
Windosw via c 스터디12장
Windosw via c 스터디12장Windosw via c 스터디12장
Windosw via c 스터디12장
 
Windosw via c/c++ 스터디5장
Windosw via c/c++ 스터디5장Windosw via c/c++ 스터디5장
Windosw via c/c++ 스터디5장
 
Windosw via c 스터디2장
Windosw via c 스터디2장Windosw via c 스터디2장
Windosw via c 스터디2장
 

Windows via c/c++ 스터디9장

  • 2. 1. 대기 함수들 이 함수를 호출한 스레드가 어떻게 다시 스케줄이 가능하게 되었는지를 리턴함. 리턴값 설명 WAIT_OBJECT_0 스레드가 대기하던 오브젝트가 시그널 되었음. WAIT_TIMEOUT 타임아웃 발생. WAIT_FAILED 파라미터가 잘못 입력됨.
  • 3. 1. 대기 함수들 bWaitAll ▶ 함수의 동작 방식을 결정하는 매개변수 ▶ TRUE -> 모든 오브젝트들이 시그널 상태가 될때 까지 스레드를 대기 상태로 둠, 반환 값은 WAIT_OBJECT_0가 반환됨 ▶ FALSE -> 지정한 오브젝트 들 중 단 하나라도 시그널 상태가 되면 함수 반환, 반환 값은 WAIT_OBJECT_0 ~ bWaitAll-1 사이 숫자로 결정됨
  • 4. 2. 성공적인 대기의 부가적인 영향 • 성공적인 호출을 통해 오브젝트의 상태가 변경되는 것을 일컬어 ‘성공적인 대기의 부가적인 영향’이라고 한다.
  • 5. 3. 이벤트 커널 오브젝트
  • 6. 3. 이벤트 커널 오브젝트 •다른 프로세스에서 수행되는 스레드의 경우 pszName매개변수로 전달하는 이름을 이용하거나, 상속, DuplicateHandle 함수 등을 사용하여 동일한 커널오브젝트에 접근할 수 있다. •또는 OpenEvent 함수에 pszName매개변수에 지정한 이름을 매개변수로 전달하여 동일한 이벤트에 접근할 수 있다.
  • 7. 3. 이벤트 커널 오브젝트
  • 8. 3. 이벤트 커널 오브젝트
  • 9. 3. 이벤트 커널 오브젝트 핸드셰이크 예제 애플리케이션 •https://github.com/cggos/windows_via_cpp/tree/master/09-Handshake
  • 10. 4. 대기 타이머 커널 오브젝트
  • 11. 4. 대기 타이머 커널 오브젝트 대기 타이머를 이용하여 APC 요청을 스레드의 APC 큐에 삽입하는 방법
  • 12. 4. 대기 타이머 커널 오브젝트
  • 13. 4. 대기 타이머 커널 오브젝트
  • 14. 4. 대기 타이머 커널 오브젝트 타이머와 관련된 미결 문제 •타이머는 종종 통신 프로토콜을 구현하는데 사용되기도 한다. 이때, 매 요청별로 타이머 커널 오브젝트를 생성하게 되면 시스템의 성능이 저하될 수도 있기 때문에 가능하다면 하나의 타이머 오브젝트만을 생성하고, 시그널 시간을 적절히 변경해 가면서 재사용하는 것이 좋다. •직접 타이머 시간을 변경하고 재설정하는 작업을 수행하는 대신 새롭게 추가된 스테드 풀링 함수의 하나인 CreateThreadpoolTimer와 같은 함수를 사용한다. •윈도우 개발에 익숙한 개발자라면 대기 타이머와 유저타이머(SetTimer 함수를 사용하는)를 비교해 보려 할 것이다. 가장 큰 차이점은 유저 타이머의 경우 비교적 리소스를 많이 사용하는 사용자 인터페이스 환경 하에서만 수행된다는 것이다. 대기 타이머는 커널 오브젝트이기 때문에 다수의 스레드에 의해 공유될 수 있으며, 좀더 보안에 안정적이다.
  • 15. 5. 세마포어 커널 오브젝트 •세마포어 커널 오브젝트는 리소스의 개수를 고려해야 하는 상황에서 주로 사용된다. •세마포어는 다음의 규칙에 따라 동작한다. 1. 현재 리소스 카운트가 0보다 크면 세마포어는 시그널 상태가 된다. 2. 현재 리소스 카운트가 0이면 세마포어는 논시그널 상태가 된다. 3. 시스템은 현재 리소스 카운트를 음수로 만들 수 없다. 4. 현재 리소스 카운트는 최대 리소스 카운트보다 커질 수 없다. • 세마포어를 사용할 때에는 오브젝트의 사용 카운트와 현재 리소스 카운트를 혼돈하지 않도록 주의해야 한다.
  • 16. 5. 세마포어 커널 오브젝트 •세마포어 커널 오브젝트를 생성하려면 CreateSemaphore 함수를 사용하면 된다. •현재는 아래와 같이 변경되었음.
  • 17. 5. 세마포어 커널 오브젝트 •CreateSemaphoreEx 함수를 이용하면 dwDesiredAccess 매개변수를 통해 세마포어에 대한 접근권한을 바로 지정할 수 있다
  • 18. 5. 세마포어 커널 오브젝트 •모든 프로세스는 OpenSemaphore 함수를 이용하여 이미 생성된 세마포어를 가리키는 프로세스 고유의 핸들값을 얻을 수 있다.
  • 19. 5. 세마포어 커널 오브젝트 •세마포어의 현재 리소스 카운트를 증가시키기 위해서는 ReleaseSemaphore 함수를 호출하면 된다.
  • 20. 6. 뮤텍스 커널 오브젝트 •뮤텍스 커널 오브젝트는 스레드가 단일의 리소스에 대해 배타적으로 접근할 수 있도록 해 준다. 사실 뮤텍스(MUTual EXclusion)이라는 이름도 이러한 특성으로부터 기인한 것이다. 이 커널 오브젝트는 사용 카운트, 스레드ID, 반복 카운터를 저장할 수 있는 공간을 가지고 있다. •뮤텍스의 동작 방식은 크리티컬 섹션과 동일하다. 하지만 크리티컬 섹션이 유저 모드 동기화 오브젝트인 데 반해 뮤텍스는 커널 오브젝트라는 차이점이 있다. 이러한 차이점 때문에 뮤텍스는 크리티컬 섹션에 비해 느리지만, 서로 다른 프로세스에서 동일 뮤텍스에 대해 접근이 가능하며, 리소스에 대한 접근 권한을 획득할 때 시간 제한을 지정할 수 있다는 장점이 있다. •스레드 ID : 시스템 내의 어떤 스레드가 뮤텍스를 소유하고 있는지를 나타내는 값이다. •반복 카운터 : 뮤텍스를 소유하고 있는 스레드가 몇 회나 반복적으로 뮤텍스를 소유하고자 했는지에 대한 횟수를 나타내는 값이다. •뮤텍스는 다수의 스레드가 동시에 접근하는 메모리 블록을 보호하기 위해 사용되기도 한다. •뮤텍스는 다음의 규칙에 따라 동작한다. 1. 스레드ID가 0(유효하지 않는 스레드ID)이면 뮤텍스는 어떠한 스레드에 의해서도 소유되지 않은 것이며, 이때 뮤텍스는 시그널 상태가 된다. 2. 스레드ID가 0이 아니면 뮤텍스는 특정 스레드에 의해 소유된 것이며, 이때 논시그널 상태가 된다. 3. 다른 커널 오브젝트와는 다르게 뮤텍스는 특수한 코드를 포함하고 있어서 일반적인 규칙을 위반하는 경우도 있다.
  • 21. 6. 뮤텍스 커널 오브젝트 •뮤텍스를 사용하려면 CreateMutex 함수를 호출해서 뮤텍스를 생성해야 한다. • 아래 함수의 dwDesiredAccess 파라미터를 통해 뮤텍스에 대한 접근 권한을 바로 지정할 수 있다 • 모든 프로세스는 OpenMutex 함수를 이용하여 이미 생성된 뮤텍스를 가리키는 프로세스 고유의 핸들값을 얻을 수 있다.
  • 22. 6. 뮤텍스 커널 오브젝트 •리소스에 대한 접근 권한을 획득한 스레드가 더 이상 리소스를 사용할 필요가 없어지면 반드시 ReleaseMutex 함수를 호출하여 뮤텍스의 소유권을 해제해 주어야 한다
  • 23. 6. 뮤텍스 커널 오브젝트 ① 버림 문제 (Abandonment issues) •뮤텍스는 다른 모든 커널 오브젝트와는 다르게 "스레드 소유권(thread ownership)"의 개념을 가지고 있다. 뮤텍스만이 어떤 스레드가 성공적인 대기를 수행하였는지를 기록해 둔다. 이러한 뮤텍스의 스레드 소유권이라는 개념 때문에 뮤텍스가 논 시그널 상태임에도 불구하고 스레드가 뮤텍스를 다시 소유할 수 있는 예외적인 규칙을 가지게 된 것이다. •뮤텍스와 스레드 커널 오브젝트를 계속해서 추적하고 있기 때문에 언제 뮤텍스가 벼려졌는지(소유권을 해제하지 않고 스레드 종료) 정확히 알 수 있으며, 뮤텍스의 버림이 발생하면 버려진 뮤텍스의 스레드 ID와 반복 카운트를 0으로 변경한다. 이 경우 대기 함수는 WAIT_ABANDONED라는 특별한 값을 반환한다
  • 24. 6. 뮤텍스 커널 오브젝트 ② 뮤텍스와 크리티컬 섹션
  • 25. 6. 뮤텍스 커널 오브젝트 •③ 큐 예제 애플리케이션
  • 26. 7. 편리한 스레드 동기화 오브젝트 표

Editor's Notes

  1. ■ 유저 모드 동기화 메커니즘에 비해 느린 편이지만 유저 모드 동기화 메커니즘에 비해 폭넓게 사용 가능 다른 프로세스간 사용 가능 ■ 해당 함수들은 유저 모드에서 커널 모드로의 전환을 필요로 함 -> 커널 모드에서 수행하는 작업을 완전히 배제 하더라도 x86 플랫폼에서 약 200CPU 사이클 정도가 필요한 비싼 작업 -> 새로운 스레드가 모든 캐시를 비우고 스케줄링 되기 위해선 수만 사이클 필요 ■ 대부분의 커널 오브젝트는 동기화를 위해 사용될 수 있다 -> 모든 커널 오브젝트는 시그널, 논시그널 상태가 될 수 있다 ▶ 시그널 : 사용 가능 상태 ▶ 논시그널 : 사용 불가 상태
  2. ■ 대기 함수를 호출하면 인자로 전달한 커널 오브젝트가 시그널 상태가 될 때 까지 이 함수를 호출한 스레드를 대기 상태로 유지 -> 만일 대기 함수가 호출된 시점에 커널 오브젝트가 이미 시그널 상태 였다면 스레드는 대기 상태로 전환되지 않는다 -> 대기 상태 없이 바로 반환되서 코드 실행 ▶ 해당 함수의 반환 값은  이 함수를 호출한 스레드가 어떻게 다시 스케줄 가능하게 되었는지 이유를 알려준다 -> 대기하던 스레드가 다시 스케줄 된 이유 dwMilliseconds ▶ 매개 변수는 커널 오브젝트가 시그널 상태가 될 때까지 얼마나 오랫동안 기다려 볼 것인지를 나타내는 시간값 ▶ INFINITE를 주로 매개 변수로 전달하지만 조금 위험 -> 만일 바라보는 커널 오브젝트가 시그널 상태가 되지 못한다면 이 함수를 호출한 스레드는 절대로 깨어나지 못하기 때문 ▶ 0으로 전달하는 경우는 바라보는 커널 오브젝트의 상태를 확인하지 않고 그냥 바로 반환 -> 코드 바로 실행 WaitForSingleObject의 반환 값은 이 함수를 호출한 스레드가 어떻게 다시 스케줄 가능하게 되었는 지를 알려준다. 만일 스레드가 대기하던 오브젝트가 시그널되었다면 반환 값은 WAIT_OB]ECT_O 가 되며, 타임아웃이 발생하였다면 반환 값은 WAIT TIMEOUT이 된다. 만일 잘못된 인자를 WaitForSingleObject 함수에 전달하였다면(유효하지 않은 핸들을 전달한 것과 같이 ) WAIT FAILED 를 반환 한다( GetLastEr or를 호출해 보면 자세한 정보를 획득할 수 있다).
  3. ▶ WaitForSingleObject와 매우 유사하지만 해당 함수는 여러 커널 오브젝트를 바라보며 기다릴 수 있음 -> 2번째 매개 변수로 바라 봐야할 커널 오브젝트들의 배열을 전달 ▶ 두가지 방법으로 대기 가능 1) 전달된 모든 커널 오브젝트들이 시그널 상태가 될 때 까지 대기하는 방법 2)전달된 커널 오브젝트들 중 하나라도 논 시그널이 되면 실행 bWaitAll ▶ 함수의 동작 방식을 결정하는 매개변수 ▶ TRUE -> 모든 오브젝트들이 시그널 상태가 될때 까지 스레드를 대기 상태로 둠,  반환 값은 WAIT_OBJECT_0가 반환됨 ▶ FALSE -> 지정한 오브젝트 들 중 단 하나라도 시그널 상태가 되면 함수 반환, 반환 값은 WAIT_OBJECT_0 ~ bWaitAll-1 사이 숫자로 결정됨
  4. 성공적인 호출 : 매개변수로 전달한 커널 오브젝트가 시그널 상태가 되어 WAIT_OBJECT_0을 반환하는 경우 성공적이지 않은 호출 : WAIT_TIMEOUT이나 WAIT_FAILED를 반환하는 경우를 말하며 오브젝트의 상태가 변경되지 않는다. ① 자동 리셋 이벤트 커널 오브젝트 핸들을 매개변수로 대기 함수를 호출하는 경우, 이 오브젝트가 시그널 상태가 되면 WAIT_OBJECT_0을 반환한다 ② 함수가 반환되기 직전에 ‘성공적인 대기의 부가적인 영향’ 으로 인해 이벤트 커널 오브젝트는 논시그널 상태로 변경될 것이다. WaitForMultipleObjects 가 호출되었을 당시에는 두 개의 오브젝트가 모두 논시그널 상태이기 때문에 스레드는 대기 상태에 진입하게 된다. 이제 hAutoResetEvent1이 시그널 상태가 되었다고 하자. 대기 상태에 진입한 두 개의 스레드는 동시에 이 오브젝트가 시그널 상태가 되었음을 감지하겠지만, hAutoResetEvent2 가 시그널 상태가 되지 않았기 때문에 깨어나지 못한다. 아직까지 성공적인 대기가 수행 되지 않았으며, 따라서 hAutoResetEvent1에 대한어떠한부가적인 영향도발생하지 않는다. 이제 hAutoResetEvent2 오브젝트가 시그널 상태가 되었다고 하자. 이때 두 개의 스레드 중 하나만 이 자신이 대기 중인 두 개의 오브젝트가 모두 시그널 상태가 되었음을 인지하게 된다. 성공적인 대 기가 수행되었으므로 두 개의 오브젝트는 모두 논시그널 상태로 변경되고 스레드는 스케줄 가능 상태가 된다. 그렇다면 다른 스레드는 어떻게 되는 것인가? 이 스레드는 앞서 hAutoResetEvent1이 시그널 상태가 된 것을 알고 있었음에도 불구하고 계속해서 두 개의 오브젝트가 다시 시그널 상태가 될 때까지 대기 상태에 머물게 된다. 이제 이 스레드가 바라보는 못한다hAutoResetEvent1 오브젝트는 다 시 논시그널 상태가 되었다. 앞서 설명한 것처 럼 WaitForMultipleObjects 가 원자적으로 동작된다는 사실은 매우 중요하다. 이 함 수가 내부적으로 커널 오브젝트들의 상태를 확인하는 시점에는 다른 어떤 스레드도 오브젝트들의 상태를 변경하지못한다. 이렇게 함으로써 데드락이 발생하는 것을 미연에 방지할 수 있다. 만일 어떤 스레드가 hAutoResetEvent1이 시그널 상태가 되었음을 발견하고 이 이벤트를 논시그널 상태로 변경했다고 하자. 동시에 또 다른 스레드는 hAutoResetEvent2 가 시그널 상태가 되었음을 발 견하고 이 이벤트를논시그널 상태로 변경했다고 하자. 이러한상황이 발생하면 다른스레드가소유한 이벤트에 대한 순환 대기가 발생하기 때문에 스레드들은 완전히 정지해 버리게 된다. 하지만 WaitForMultipleObjects를 호출하는 경우에는 절대로 이런 일이 발생하지 않는다. 이때 깨어나는 스레드는 어떤 스레드 인가에 대해서 우선순위나 대기시간은 영향을 주지 않으며 마이크로소프트는 선입선출 방식을 사용하고 있다.
  5. 모든 커널 오브젝트 중 이벤트가 가장 단순한 구조를 가진다. 사용카운트, 자동리셋인지 수동리셋인지를 판별하는 bool값, 이벤트가 시그널 상태인지 논시그널 상태인지를 나타내는 bool값으로 구성되어있다. 이벤트는 어떤 작업이 완료되었음을 알리기 위해 주로 사용되며 수동 리셋 이벤트와 자동 리셋 이벤트의 서로 다른 두 가지 형태가 있다. 수동 리셋 이벤트가 시그널 상태가 되면 이 이벤트를 기다리고 있던 모든 스레드들은 동시에 스케줄 가능 상태가 된다. 자동 리셋 이벤트의 경우에는 대기 중인 스레드들 중 하나의 스레드만이 스케줄가능 상태가된다. 이벤트는 하나의 스레드가 초기 작업을 수행하고 이후 다른 스레드에게 나머지 작업을 수행할 것을 알려주기 위해 사용하는 경우가 많다. 이 경우 이벤트는 논시그널 상태로 초기화되고, 스레드가 초기 작업 수행을 마쳤을 때 시그널 상태로 만든다. 이때 이벤트가 시그널 상태가 되기를 기다리던 두 번 째 스레드는 시그널 상태를 감지하여 첫 번째 스레드의 작업이 완료되었음을 인지하고 스케줄 가능 상태가된다. 위 함수에서 첫번째 파라미터와 네번째 파라미터는 커널오브젝트를 설명할때 나왔던 것들이고 bManualReset 매개변수는 부울 값으로 시스템에게 수동 리셋 이벤트(TRUE)를 생성할 것인지, 자동 리셋 이벤트(FALSE)를 생성할 것인지의 여부를 전달하게 된다 blnitialState 매개변수로는 이벤트의 초기 상태를 시그널 상태 (TRUE)로 만들 것인지, 논시그널 상태 (FALSE)로 만들 것인지를 결정하는 값을 전달하게 된다. 시스템은사용자의 요청에 따라 커널 오브젝트를생성한후 CreateEvent의 반 환 값으로 이벤트 오브젝트를 나타내는 프로세스 고유의 핸들 값을 반환한다. CreateEnventEx 는 Vista부터 제공되는 함수이다. psa와 pszName 매개변수는 CreateEvent와 통일한 의미를 가진다. dwFlags 매개변수로는 두 개 의 비트마스크 값을 전달하게 되는데 이에 대해서는 표로 나타냄.
  6. 이벤트 커널 오브젝트를 더 이상 사용할 펼요가 없다면 CloseHandle 함수를 호출해야 한다. 일단 이벤트가 생성되면 이벤트의 상태를 바로 제어 할 수 있다. 이벤트를 시그널 상태로 변경하려 면 SetEvent 함수를 사용하면 된다. 마이크로소프트는 두 가지 형태의 이벤트 중 자동 리셋 이벤트에 대해서만 성공적인 대기의 부가적 인 영향을 정의하고 있다. 만일 자동 리셋 이벤트에 대해 성공적인 대기가 이루어지변 자동적으로 이 벤트의 상태는논시그널 상태로 바뀐다. 이러한동작방식 때문에 이 이벤트를자동 리셋 이벤트라고 명명한 것이다. 보통의 경우 자동 리셋 이벤트에 대해서는 시스뱀이 자동적으로 리셋을 수행하기 때 문에 따로 ResetEvent를 호출할 필요가 거의 없다. 반면 마이크로소프트는 수동 리셋 이벤트에 대 해서는 성공적인 대기의 부가적인 영향을 정의하지 않고 있다.
  7. 이벤트 커널 오브젝트를 이용하여 어떻게 스레드 동기화를 수행하는지 예제를 통해 빠르게 확인해 보자. 아래의 예제 코드를보라. 이 코드를 수행하면 수동 리셋 이벤트를 논시그널 상태로 생성하고 이에 대한 핸들을 전역변수에 저 장하여 다른 스레드에서도 동일 이벤트에 대해 쉽게 접근할 수 있도록 한다.3 개의 새로운 스레드가 생성되고, 각 스레드들은 파일의 내용이 메모리로 로드될 때까지 대기하다가 로드가 완료되면 메모 리에 접근한다. 첫 번째 스레드는 단어의 개수를 세고, 두 번째 스레드는 철자법을 검사하고, 세 번째 스레드는 문법을 검사하는 기능을 수행한다고 생각해 보자. 각각의 스레드 함수는 모두 독립적으로 구성되어 있으며, 주 스레드가 파일의 내용을 메모리로 모두 로드할 때까지 WaitForSingleObject 함 수를호출하여 대기 상태를유지하도록작성되었다. 주 스레드가 파일의 내용을 완전히 메모리로 로드하면 SetEvent 함수를 호출하여 이벤트를 시그널 상태로 만든다. 이때 대기 중인 세 개의 스레드는 모두 스케줄 가능 상태로 변경되며, CPU 시간을 얻게 되면 메모리에 접근하게 된다. 세 개의 스레드는 모두 메모리의 내용을 변경하지 않고 읽기만 하 기 때문에 스레드들이 동시에 메모리에 접근하여도 문제가 되지 않는다. 만일 컴퓨터가 여러 개의 CPU를 가지고 있는 경우라면 실제로 각 CPU에 의해 세 개의 스레드가 동시에 수행될 것이며, 좀 더 짧은시간에 작업이 완료될 것이다. 만일 수동 리셋 이벤트 대신 자동 리셋 이벤트를 사용하게 되면 애플리케이션의 동작 방식이 일부 변 경된다. 주 스레드가 SetEvent를 호출하게 되면 이벤트가 시그널 상태가 되기를 기다리는 세 개의 스레드 중 유일하게 한 개의 스레드만이 스케줄 가능 상태가 되며 나머지 두 개의 스레드는 계속해 서 이벤트가 시그널 상태가 되기를 기다리게 된다. 다시 말하지만 어떤 스레드가 스케줄될지는 전혀 알수없다. 스케줄 가능 상태가 된 스레드는 메모리 블록에 배타적으로 접근할 수 있게 된다. 스레드 함수를 수정하여 함수가 반환되기 직전에 SetEvent를 호출하도록 해 보자 tWinMain 함수에서 한 것과 같이). 스레드 함수를 다음과 같이 변경하면 된다.
  8. 수행 기회를 얻은 스레드가 메모리 사용을 끝내고 SetEvent를 호출하면 시스템은 이벤트가 시그널 되기를 기다리는 두 개의 스레드 중 하나를 선택하여 스케줄 가능 상태로 변경하게 된다. 물론 이때 에도 어떤 스레드가 선택될지는 알 수 없다. 이 스레드 또한 배타적으로 메모리에 접근할 수 있으며, 작업을 마치면 SetEvent를 호출하게 된다. 이제 마지막 스레드가 수행되며 작업을 수행하게 된다. 자동 리셋 이벤트를 사용하였을 경우에는 새로 생성된 세 개의 스레드들이 메모리에 대해 읽고 쓰기를 마음대로 할 수 있다는 것에 주목할 펼요가 있다. 이 예제는 수동 리셋 이벤트와 자동 리셋 이벤트의 차이점을 명확하게 보여주고 있다.
  9. https://github.com/cggos/windows_via_cpp/tree/master/09-Handshake 핸드셰이크 애플리케이션은 요청 문자열을 받아서 문자열 내의 각 문자의 위치를 뒤집는 역할을 수 행하며, 그 결과를 Result 필드에 나타낸다. 핸드셰이크 애플리케이션은 전형적인 프로그래밍 문제를 해결하는 방법을 보여준다. 서로 통신해야 하는 클라이언트와 서버가 있다고 할 때 클라이언트는 서버와 클라이언트가 공유할 수 있는 메모리 공간에 요청을 저장하고, 서버에게 그 내용을 처리하도록 알려주게 된다. 서버 스레드가 요청을 처리 하는동안클라이언트는 대기 상태에 머물게 된다. 서버 스레드는 클라이언트의 요청을모두 처리한 후 특정 이벤트를 시그널 상태로 만들어서 클라이언트에게 요청이 모두 처리되었음을 알려준다. 클라이언트의 수행이 재개되면 공유 데이터 버퍼에 결과가 있음을 알게 되고 그 결과를 사용자에게 전달할수있다. 예제에서는
  10. 대기 타이머는 특정 시간에 혹은 일정한 간격을 두고 자신을 시그널 상태로 만드는 커널 오브젝트로, 주로 특정 시간에 맞추어 어떤 작업을 수행해야 할 경우에 사용된다. 대기 타이머를 생성하려면 단순히 Create WaitableTimer를 호출하면 된다. bManualReset 매개변수로는 수동 리셋 타이머를 생성할 것인7-1 아니면 자동 리셋 타이머인지를 생 성할 것인지를 결정하는 값을 전달한다. 자동 리셋 타이머가 시그널 상태가 되면 이 타이머를 대기 중인 스레드들 중 유일하게 한 개의 스레드만이 스케줄 가능 상태가 된다. psa와 pszName 매개변수는 장에서 논의한 바 있다. 다른 프로세스에서는 Open WaitableTimer 함수를이용하여 이미 생성된 대기 타이머를 가리키는 프로세스고유의 핸들값을 얻을수 있다. 대기 타이머는 항상 논시그널상태로 생성되며, 언제 시그널 상태가 될 것인지를 지정하기 위해 SetWaitableTimer 함수를 시용한다. hTimer 매개변수는 설정하고자 하는 대기 타이머를 나타내는 핸들 값이다. 두 번째 매개변수인 pDueTime과 lPeriod 는 항상 같이 사용되는데, pDueTime은 시그널 상태가 되는 최초 시간을 lPeriod는 그 후 얼마의 주기로 시그널 상태를 반복할 것인지를 지정한다.
  11. 마이크로소프트는 SetWaitableTimer를 이용하여 타이머가 시그널 상태가 되었을 때 비동기 함수 호출(APC) 요청을 스레드의 APC 큐에 삽 입할 수 있는 방법을 제공하고 있다. 보통의 경우 SetWaitableTimer를 호출할 때 pfnCompletionRoutine과 pv ArgToCompletionRoutine 매개변수에는 NULL 값을 지정한다. 이 매개변수들을 NULL로 지정하는 이유는 타이머가 시그널 상태가 되는 시점만을 알면 되기 때문이다. 하지만 이러한 매개변수로 APC 루틴의 주소를 전달 해 주변 타이머가 시그널 상태가 되었을 때 APC 요청을 스레드의 APC 큐에 삽입해 준다. 이 함수는 타이머가 시그널 상태가 되고 SetWaitableTimer를 호출한 스레드가 얼러터블(알림 가능한) 상태에 있는 경우 SetWaitableTimer를 호출하였던 바로 그 스레드에 의해 호출된다. 스레드를 얼러터블 상태로 만들기 위해 서는 SleepEx, WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectsEx, SignalObjectAndWait와 같은 함수를 호출하면 된다. 만일 스레드가 이와 같은 함수를 호 출하지 않아서 얼러터블 상태에 있지 않은 경우라면 시스댐은 타이머가 시그널 상태가 되어도 APC요청을 레드의 APC 큐에 삽입하지 않는다. 이는 타이머에 의해 필요 없는 APC 요청을 스레드의 APC 큐에 쌓아둠으로써 메모리를 낭비하는 것을 막기 위함이다. 만일 스레드가 얼러터블 상태 에서 대기 중이고 타이머가 시그널 상태가 되면, 시스템은 이 스레드를 이 용하여 APC 콜백 루틴을 호출한다. 콜백 루틴의 첫 번째 매개변수에는 SetWaitableTimer 호출 시에 pv ArgToCompletionRolltine 매개변수로 전달한 값과 동일한 값이 전달된다. 보통 TimerAPCROlltine 에 컨텍스트 정보를 전달하기 위해 이 매개변수를 활용한다(일반적으로 사용자가 정의한 구 조체의 주소를 전달한다). 나머지 두 개의 매개변수인 dwTimerLowVallle 와 dwTimerHigh Vallle 로는 타이머가 언제 시그널 상태가 되었는지를 알려주는 정보가 전달된다.
  12. 방금 설명한 것들을 사용자에게 보여주는 예제코드이다.
  13. 큐에있는 APC 요청들이 모두 처리되어야 비로소 얼러터블 함수가 반환되기 때문에 TimerAPCRoutine 함수는 다음번 APC 요청이 APC 큐에 삽입되기 전에 처리를 마치고 반환되도록 작성되어야한다. 아래에 타이머와 APC를 적절하게 사용하는 코드의 예를 나타냈다. 마지막으로, 스레드는 단일의 타이머 핸들에 대해 타이머 커널 오브젝트에 대한 시그널 대기와 얼러터블 상태 대기를 동시에 수행해서는 안 된다. 예시)아래코드 절대 위와 같이 코드를 작성해서는 안 된다. 이렇게 되면 WaitForSingleObjectEx는 커널 오브젝트 핸들에 대한 시그널 대기와 얼러터블 상태 대기와 같이 2번의 대기를 수행하는 꼴이 된다. 만일 위와 같이 코드를 작성한 상태에서 타이머가 시그널 상태가 되면 성공적인 대기가 수행되어 스레드가 깨어 나게 되고 얼러터블상태에서 벗어나기 때문에 APC 루틴은호출되지 않는다. 앞서 말한바와같이 타이머가 시그널 상태가 되는 것을 기다렸다가 작업을 수행해도 되는 경우라면 굳이 APC 루틴을 시용할 필요가없 을것이다.
  14. 타이머는 종종 통신 프로토콜을 구현하는데 사용되기도 한다. 이때, 매 요청별로 타이머 커널 오브젝트를 생성하게 되면 시스템의 성능이 저하될 수도 있기 때문에 가능하다면 하나의 타이머 오브젝트만을 생성하고, 시그널 시간을 적절히 변경해 가면서 재사용하는 것이 좋다. 직접 타이머 시간을 변경하고 재설정하는 작업을 수행하는 대신 새롭게 추가된 스테드 풀링 함수의 하나인 CreateThreadpoolTimer와 같은 함수를 사용한다. 윈도우 개발에 익숙한 개발자라면 대기 타이머와 유저타이머(SetTimer 함수를 사용하는)를 비교해 보려 할 것이다. 가장 큰 차이점은 유저 타이머의 경우 비교적 리소스를 많이 사용하는 사용자 인터페이스 환경 하에서만 수행된다는 것이다. 대기 타이머는 커널 오브젝트이기 때문에 다수의 스레드에 의해 공유될 수 있으며, 좀더 보안에 안정적이다.
  15. 세마포어 커널 오브젝트는 리소스의 개수를 고려해야 하는 상황에서 주로 사용된다. 이 커널 오브젝트는 모든 커널 오브젝트와 마찬가지로 사용 카운트를 가지고 있으며, 이 외에도 2개의 32비트 값을 가지고 있어서 최대 리소스 카운트와 현재 리소스 카운트를 저장하고 있다. 최대 리소스 카운트는 세마포어가 제어할 수 있는 리소스의 최대 개수를 나타내는 데 사용되고, 현재 리소스 카운트는 사용 가능한 리소스의 개수를 나타내는 데 사용된다.
  16. psa와 pszName 매개변수에 대해서는 에서 설명한 바 있다
  17. CreateSemaphoreEx 함수를 이용하 면 dwDesiredAccess 매개변수를 통해 세마포어에 대한 접근 권한을 바로 지정할 수 있다. dwFlags 매개변수는 항상 으로 설정해야 한다.
  18. 모든 프로세스는 OpenSemaphore 함수를 이용하여 이미 생성된 세마포어를 가리키는 프로세스 고유의 핸들값을 얻을수있다. 마찬가지로 유니코드일때와 아닐때로 나뉘어져 있지만 인자값은 같으므로 따로 기재하지 않았다. lMaximumCount 매개변수로는 애플리케이션에서 사용할 수 있는 리소스의 최대 개수를 지정하면 된다. 이 값은 부호 있는 32 비트 값이므로 최대 147 483 647 까지 리소스의 개수를 지정할 수 있 다lInitialCount 매개변수로는 현재 사용 가능한 리소스의 개수를 지정하면 된다. 서버가 최초로 수 행되었을 때에는 어떠한 클라이언트의 요청도 없을 것이므로 CreateSemaphore를 다음과 같이 호출할수있다. 이와 같이 세마포어를 생성하면 최대 리소스 카운트를 5로 사용 가능한 현재 리소스 카운트를 0으로 생성하게 된다. (하지만 커널 오브젝트의 사용 카운트 값은 커널 오브젝트가 방금 생성되었기 때문에 1이 된다. 혼돈하지 않도록 주의하라.) 현재 리소스 카운트가 0이기 때문에 세마포어는 논시그널 상태 가 된다. 따라서 세마포어가 시그널 상태가 될 를 기다리는 모든 스레드들은 대기 상태가 된다. 스레드가 리소스에 대한 접근을 요청하기 위해 대기 함수를 호출할 때에는 세마포어의 핸들을 전달하 면 된다. 대기 함수는 내부적으로 세마포어의 현재 리소스 카운트 값을 확인하여 이 값이 보다 크면 값을 1만큼 감소시키고 대기 함수를 호출한 스레드를 스케줄 기능 상태 로 만든다. 세마포어의 현재 리소스 카운트 값을 확인하고 그 값을 변경하는 등의 모든 동작은 원자적으로 수행된다. 세마포어를 통해 리소스에 대한 접근을 시도하게 되면 운영체제는 사용 가능 리소스를 확인하고 현재 리소스 카운트 값을 감소시키게 되는데 이러한 동작들은 다른 스레드의 간섭을 전혀 받지 않으며, 현재 리소스 카운트 값이 감소된 이후에야 비로소 다른 스레드의 리소스에 대한 접근 요청을 받아들인다. 만일 대기 함수가 세마포어의 현재 리소스 카운트 값이 0임을 확인하게 되면 대기 함수를 호출한 스레드를 대기 상태로 유지한다. 다른 스레드가 세마포어의 현재 리소스 카운트를 증가시켜 주면 비로소 대기 상태에 있던 스레드가 스케줄 가능 상태로 바뀐다(이때 당연히 사용된 리소스 개수만큼 현재 리소스 카운트는 감소한다).
  19. 세마포어의 현재 리소스 카운트를 증가시키기 위해서는 ReleaseSemaphore 함수를 호출하면 된다. 이 함수는단순히 lReleaseCount에 지정된 값만큼 세마포어의 현재 리소스카운트 값을 증가시키는 역할을 수행한다. 보통의 경우 lReleaseCount 매개변수로 1을 전달하지만 항상 그렇게 사용해야 하는 것은 아니다. 실제로 2나 그 이상의 수를 사용하기도 한다. 이 함수는 *lpPreviousCount로 증가 되기 이전의 현재 리소스 카운트 값을 반환해 준다. 사실 애플리케이션 개발 시 이 값을 사용하는 경우 는 상당히 드물다. 다행히도 이 매개변수로 NULL 값을 전달할 수도 있다. ReleaseCount로 0을 넣거나 최대 카운트이상의 수를 넣어서 증가를 막고 리소스 카운트만 가져올 수는 없다. 카운트를 변화없이 현재 카운트를 가져오는데에 사용할 수는 없다.
  20. 뮤텍스를 사용하려면 CreateMutex 함수를 호출해서 뮤텍스를 생성해야 한다. 아래의 CreateMutexEx 함수를 이용하면 dwDesiredAccess 파라미터를 통해 뮤텍스에 대한 접근 권한을 바로 지정할 수 있다. dwFlags 매개변수는 CreateMutex의 blnitialOwner 매개변수와 동일한 용도로 사용된다: blnitialOwner 매개변수는 뮤텍스의 초기 상태를 제어히는 용도로 사용된다. 이 값을 FALSE(보통 의 경우)로 설정하면 뮤텍스의 스레드 ID와 반복 카운터는 0으로 설정된다. 이것은 뮤텍스가 어떠한 스레드에 의해서도 소유되지 않았으며 시그널 상태임을 나타내게 된다. 만일 blnitialOwner 값을 TRUE로 설정하게 되면 뮤텍스의 스레드 ID는 함수를 호출한 스레드의 ID 로 설정되며, 반복 카운터는 1로 설정된다. 스레드 ID가 0이 아니므로 뮤텍스는 논시그널 상태가 된다.
  21. 이 함수는 오브젝트의 반복 카운터 값을 만큼 감소시킨다. 만일 동일 뮤텍스에 대해 통일 스레드가 여러 번에 걸쳐 성공적인 대기를 수행한 경우라면 스레드는 동일 횟수만큼 ReleaseMutex를 호출해 야만뮤텍스의 반복카운터 값을 0으로만들수 있다. 반복카운터 값이 이 되면 스레드 ID 값도 0 으로 변경되고, 뮤텍스 오브젝트는 시그널 상태로 변경된다. 뮤텍스 오브젝트가 시그널 상태가 되면 시스템은 동일 뮤텍스를 기다리고 있는 다른 스레드들이 있는지 확인한다. 만일 대기 중인 스레드들이 여러 개 있는 경우 이 중 하나를 “공평하게” 선택하여 뮤텍스를 소유하도록 한다. 이러한 절차는 뮤텍스의 스레드 ID 값을 선택된 스레드의 ID 값으로 변경 하고 반복 카운터 값을 로 설정하는 과정을 통해 수행된다. 만일 어떠한 스레드도 뮤텍스를 기다리고 있지 않다면, 추후 뮤텍스를 소유하고자 하는 스레드가 즉각적으로 이를 소유할 수 있도록 시그널 상태를유지하게된다.