Server/C++

커널 오브젝트 Event를 사용한 프로그램 동작

Juzdalua 2024. 7. 30. 15:57

프로세스: 실행중인 프로그램

Event를 통해 스케줄링된 프로그램은 해당 이벤트에게 실행권을 받을 때까지 실행할 수 없고 대기상태로 존재한다.

1. 유저레벨에서 현재 실행중인 프로세스가 종료되고 커널레벨의 이벤트를 Signal상태로 변경한다..

2. 커널레벨의 이벤트는 스케줄링 되어있던 다음 프로그램에게 실행권을 넘긴다.

3. 대기중이던 프로그램은 CPU 코어를 할당받고 프로세스 동작을 실행한다.


커널 오브젝트

이벤트는 커널에서 관리하는 커널오브젝트이다.

// 커널 오브젝트의 공통 속성
int Usage Count: 현재 이벤트를 사용중인 갯수
Bool Signal / Non-Signal: 현재 이벤트의 on/off 여부

// 이벤트의 속성
Bool Auto/Manual: 이벤트의 자동/수동모드 여부

 

이벤트 

#include <windows.h>

// 이벤트 생성
EventId = CreateEvent(보안속성, bool 수동리셋 여부, bool 이벤트의 초기상태, 이름)

2. True: Manual / False: Auto -> 이벤트 활성화 후, Non-Signal 변경시 자동화 여부
3. Initial State => Signal / Non-Signal

// 이벤트 활성화 -> Signal상태로 변경
SetEvent(EventId);

// 이벤트를 활용한 대기상태 -> Signal상태면 진행, Non-Signal상태면 대기
WaitForSingleObject(EventId, INFINITE);

// 이벤트 off -> 한번 통과한 이벤트의 상태를 Signal -> Non-Signal 상태로 변경.
// 이벤트 생성시 수동리셋(true)로 설정하면 작성해야함.
ResetEvent(EventId);

 

https://learn.microsoft.com/ko-kr/windows/win32/sync/using-event-objects

 

이벤트 개체 사용(동기화) - Win32 apps

애플리케이션은 여러 상황에서 이벤트 개체를 사용하여 대기 스레드에 이벤트 발생을 알릴 수 있습니다.

learn.microsoft.com


Event를 활용한 시스템

Event는 Lock과 별도로 동작하기 때문에 완벽하지 않다.

 

먼저 이벤트 없이 작동하는 queue 시스템을 구현해보자.

#include "pch.h"
#include "CorePch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <windows.h>

mutex m;
queue<int32> q;

void Producer() {
	while (true) {
		{
			unique_lock<mutex> lock(m);
			q.push(100);
		}
		this_thread::sleep_for(1'000'000ms);
	}

}

void Consumer() {
	while (true) {
		unique_lock<mutex> lock(m);
		if (q.empty() == false) {
			int32 data = q.front();
			q.pop();
			cout << data << endl;
		}
	}
}

int main()
{
	thread t1(Producer);
	thread t2(Consumer);

	t1.join();
	t2.join();
}

Producer 함수는 10초에 한 번씩 데이터를 삽입하지만 Consumer 함수는 계속해서 데이터를 확인한다.

Consumer함수는 의미 없이 CPU를 계속 할당 받아 낭비되는 프로그램이다.

 

커널 오브젝트인 이벤트를 활용하여 작동하는 큐 시스템을 만들어보자.

#include "pch.h"
#include "CorePch.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <windows.h>

mutex m;
queue<int32> q;
HANDLE handle;

void Producer() {
	while (true) {
		{
			unique_lock<mutex> lock(m);
			q.push(100);
		}
		SetEvent(handle);
		this_thread::sleep_for(1'000'000ms);
	}

}

void Consumer() {
	while (true) {
		WaitForSingleObject(handle, INFINITE);
		//ResetEvent(handle);

		unique_lock<mutex> lock(m);
		if (q.empty() == false) {
			int32 data = q.front();
			q.pop();
			cout << data << endl;
		}
	}
}

int main()
{
	// EventId = CreateEvent(보안속성, bool 수동리셋 여부, bool 이벤트의 초기상태, 이름)
	handle = CreateEvent(NULL, false, false, NULL);

	thread t1(Producer);
	thread t2(Consumer);

	t1.join();
	t2.join();

	CloseHandle(handle);
}

여기서 문제점은 아래와 같다.

Produce 함수의 락 부분과 이벤트를 활성화하는 부분이 같이 동작하지 않는다.

그러므로 출력 결과를 보면 원하는 결과값을 가질 수 없게 된다.

이를 해결하기 위한 방법은 조건변수를 활용하는 방법이 있다.

https://juzdalua.tistory.com/211

 

조건변수 (Condition Variable)

Condition Variable(CV)은 유저레벨 오브젝트이다.CV는 커널레벨의 이벤트와 비슷하게 동작하지만, Lock과 짝지어 행동한다.CV는 Event의 개념과 Lock을 동시에 사용할 때 효율적이다. #include condition_variable

juzdalua.tistory.com

 

'Server > C++' 카테고리의 다른 글

Future와 Asynchronous  (0) 2024.07.30
조건변수 (Condition Variable)  (0) 2024.07.30
슬립(Sleep)과 운영체제  (0) 2024.07.30
스핀락 (Spin Lock)  (0) 2024.07.29
volatile 컴파일러 최적화  (0) 2024.07.29