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

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

박건우님의 프로필 이미지
박건우

작성한 질문수

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

Event

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

작성

·

40

·

수정됨

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 인턴입니다. 박건우님.

질문해주신 내용은 멀티스레드 환경에서 이벤트 객체의 사용과 관련된 흥미로운 문제입니다. 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] 키워드르 자료 조사를 해보세요

박건우님의 프로필 이미지
박건우

작성한 질문수

질문하기