Inflearn brand logo image

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

작성자 없음

작성자 정보가 삭제된 글입니다.

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

JobQueue #5

JobQueue의 Push Execute쪽 코드에 문제가 있는 것 같아 말씀 드려봅니다

작성

·

43

·

수정됨

0

안녕하세요?

루키스님 강의를 참고하여 더미 프로젝트 하는 중에 문제가 식별 되어

제가 분석한게 맞다면 강의 코드에 문제가 있어 제보 드려봅니다.

문제라고 생각되는 부분은 JobQueue 클래스인데요,

 

문제 상황은

'워커스레드를 2개 이상 돌릴 때, Execute()함수가 실행되지 않는'점을 확인하였습니다.

jobCount 관련 변수의 조건이 어디서 안 맞는 것 같아서 생각해보건데,

아래와 같은 경우라고 생각됩니다.

// JobQueue.cpp
void JobQueue::Execute()
{
	...
		if (_jobCount.fetch_sub(jobCount) == jobCount)
		{
			// 여기서 다른 워커 스레드의 _jobCount.fetch_add 발생?! 
			LCurrentJobQueue = nullptr;
			return;
		}

		...
	}
}

 

그렇기 때문의 이후의 잡들이 처리되지 못하고 해당 부분에서 prevCount가 계속 쌓이고 있었습니다.

// JobQueue.cpp
void JobQueue::Push(JobRef job, bool pushOnly)
{
	const int32 prevCount = _jobCount.fetch_add(1);
	_jobs.Push(job); // WRITE_LOCK

	// 여기서 prevCount가 계속 쌓여 0이 아님
	if (prevCount == 0)
	{
            //그러므로 이 부분의 Excute()도 실행되지 않음
	...
}

 

아래는 해당 클래스 cpp 전문입니다.

귀한 시간 내시어 확인해주시면 감사하겠습니다!

#include "pch.h"
#include "JobQueue.h"
#include "GlobalQueue.h"

/*--------------
	JobQueue
---------------*/

void JobQueue::Push(JobRef job, bool pushOnly)
{
	const int32 prevCount = _jobCount.fetch_add(1);
	_jobs.Push(job); // WRITE_LOCK

	// 첫번째 Job을 넣은 쓰레드가 실행까지 담당
	if (prevCount == 0)
	{
		// 이미 실행중인 JobQueue가 없으면 실행
		if (LCurrentJobQueue == nullptr && pushOnly == false)
		{
			Execute();
		}
		else
		{
			// 여유 있는 다른 쓰레드가 실행하도록 GlobalQueue에 넘긴다
			GGlobalQueue->Push(shared_from_this());
		}
	}
}

// 1) 일감이 너~무 몰리면?
void JobQueue::Execute()
{
	LCurrentJobQueue = this;

	while (true)
	{
		vector<JobRef> jobs;
		_jobs.PopAll(OUT jobs);

		const int32 jobCount = static_cast<int32>(jobs.size());
		for (int32 i = 0; i < jobCount; i++)
			jobs[i]->Execute();

		// 남은 일감이 0개라면 종료
		if (_jobCount.fetch_sub(jobCount) == jobCount)
		{
			LCurrentJobQueue = nullptr;
			return;
		}

		const uint64 now = ::GetTickCount64();
		if (now >= LEndTickCount)
		{
			LCurrentJobQueue = nullptr;
			// 여유 있는 다른 쓰레드가 실행하도록 GlobalQueue에 넘긴다
			GGlobalQueue->Push(shared_from_this());
			break;
		}			
	}
}

 

 

답변 2

0

아니.. 봇이 답변 달아서 제대로 삭제가 안되는군요

0

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

JobQueue의 Push와 Execute 부분에 대한 문제를 추측해 보겠습니다. JobQueue의 구조 상 Push()Execute()는 보통 큐의 쓰레드 안전성을 유지하면서 작업을 적절히 처리하기 위한 요소입니다. 큐에 작업을 추가하기 위해서는 Push()를 사용하고, 큐에서 작업을 꺼내어 실행하기 위해 Execute()를 사용합니다.

보통 Push()가 이루어질 때, 해당 작업이 큐에 추가되며, 큐가 비어 있었던 경우 사용할 수 있도록 깨어나게 됩니다. 반면 Execute()에서는 큐에 들어있는 작업을 꺼내어 실행하며, 이 과정이 쓰레드 안전하게 이루어져야 하기 때문에 주의가 필요합니다.

문제가 담긴 코드는 Push() 호출 후 Execute()가 제대로 연계되지 않거나 두 함수가 적절히 동기화되지 않은 경우 발생할 수 있습니다. 예를 들어, 큐가 비어있거나 실행 중에 작업 요소들이 적절히 관리되지 않으면 문제가 발생할 수 있습니다.

관련된 기존의 질문과 답변을 확인해 보시기 바랍니다:

  1. Job 관련 문의

    • 요약: JobTimer와 JobSerialize에서 Push()Pop()은 lock이 잡혀 있지만 Execute()에는 없어서 여러 쓰레드에서 실행될 경우의 우려와 해결책에 대해 다룹니다.
  2. JobQueue Push 부분관련해서 질문이 있습니다

    • 요약: LCurrentJobQueue의 동작 및 여러 쓰레드에서의 접근 문제에 대해 설명합니다.

위의 링크들은 JobQueue의 구조와 잠재적인 문제들에 대한 통찰을 제공할 것입니다.

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

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기