인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

박건우님의 프로필 이미지

작성한 질문수

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

Event

수업중 궁금한 점이 있어서 질문드립니다.

작성

·

35

·

수정됨

0

#include "pch.h"
#include <thread>
#include <atomic>
#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);
		std::this_thread::sleep_for(100ms);
	}
}
void Consumer() {

	while (true) {
	::WaitForSingleObject(handle, INFINITE);
	::ResetEvent(handle);
		unique_lock<mutex> lock(m);

		if (!q.empty()) {
			int32 data = q.front();
			q.pop();
			cout << data << endl;
		}
	}
}



int main() {

	handle = ::CreateEvent(NULL, TRUE, FALSE, NULL);
	std::thread t1(Producer);
	std::thread t2(Consumer);

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

	::CloseHandle(handle);
	return 0;
}

에서 WaitForSingleObject이후에 signal이 auto가 아니라면 ResetEvent를 따로 적어주어야 한다 하셨는데, ResetEvent가 호출되기 전에 다른 쓰레드에 있는 SetEvent가 호출되면 어떻게 되는건가요?

답변 2

1

인프런 AI 인턴님의 프로필 이미지

안녕하세요, 인프런 AI 인턴입니다. 박건우님.

질문해주신 내용은 멀티스레드 환경에서 이벤트 객체의 사용과 관련된 흥미로운 문제입니다. SetEvent, WaitForSingleObject, 그리고 ResetEvent는 윈도우즈에서 스레드 간의 동기화에 사용되는 함수들입니다.

Core Concepts:

  1. SetEvent: 이벤트 객체의 상태를 “신호 상태”로 설정합니다. 실제로 이벤트가 발생했다는 신호를 다른 스레드에 알리기 위해 사용됩니다.

  2. WaitForSingleObject: 이벤트 객체의 상태가 “신호 상태”로 될 때까지 대기합니다. 신호 상태가 될 경우, 계속 실행이 가능하게 됩니다.

  3. ResetEvent: 수동 이벤트인지 자동 이벤트인지에 따라 이벤트 객체의 상태를 “비신호 상태”로 리셋할 수 있습니다. 자동 이벤트라면 WaitForSingleObject가 호출된 뒤 자동으로 리셋됩니다. 그러나 수동 이벤트라면 사용자가 명시적으로 ResetEvent를 호출해서 리셋해야 합니다.

Scenario Analysis:

질문에서 언급하신 상황은 “SetEvent가 호출되기 전에 ResetEvent가 호출되면 어떻게 되는가?” 라는 것입니다. 예를 들어:

  • SetEvent 이후WaitForSingleObject 가 호출되고, 그 다음 ResetEvent 를 호출하면 비신호 상태로 변경되어 더 이상 다른 스레드가 해당 이벤트를 기다릴 수 없게 됩니다.

  • 그러나 ResetEvent가 호출되기 전에 SetEvent가 호출되면, 이벤트는 신호 상태에 있으며 다른 스레드들이 이 이벤트를 기다릴 때 즉시 진행할 수 있게 됩니다. 이후에 ResetEvent가 호출되면 그 이벤트는 다시 비신호 상태가 됩니다. 이 경우 수동 리셋을 이용하므로, 정확한 동기화를 위해 이 과정에서 이벤트 발생 순서를 주의 깊게 관리해야 합니다.

이상과 같은 상황은 레이스 컨디션(race condition)이 발생할 수 있으므로 프로그램의 동작을 예측하기가 어려울 수 있습니다. 따라서 이벤트 객체를 사용할 때는 어느 점에서 ResetEvent를 호출할지를 신중히 계획하는 것이 중요합니다.

해당 질문과 유사한 논의를 다룬 링크를 참고하면 도움이 될 것입니다:
- Event에 관한 질문입니다.

위 링크에서는 여러 스레드가 같이 작업할 때 이벤트 상태가 어떻게 변할 수 있는지를 설명하고 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

박건우님의 프로필 이미지
박건우
질문자

그럼 WaitForSingleObject -> SetEvent -> ResetEvent순으로 코드가 실행되면 while문을 다시 돌아서 WaitForSingleObject부분을 실행해야 할 때, q에 데이터가 있어도 non-signal 상태라서 쓰레드가 커널 모드에서 대기하는건가요?

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

Producer-Consumer는 1개 쓰레드씩 배치하는게 일반적이고,
단순한 이벤트 방식의 동기화 예제에서도 그 외 부분은 고려하지 않는데요.
Consumer를 여러개 한다면 상황은 훨씬 더 복잡해지고,
사실 그럴 때는 이 방식을 사용하지 않는게 정답입니다.

궁금하신 부분은 사실 저도 테스트 해보진 않아서 100% 확실하진 않지만
기본적으로 이벤트는 일종의 커널에서 관리하는 bool 처럼 생각하시면 됩니다.
따라서 다른 쓰레드에서 SetEvent를 했으면 Reset을 안 해도 WaitFor~에서 또 빠져 나오겠죠.

정말 궁금하시다면 이런 부분은 쓰레드를 늘려서 실험을 해보시거나,
MSDN이나 stackoverflow에 [SetEvent + threadsafe] 키워드르 자료 조사를 해보세요