JobQueue의 Push Execute쪽 코드에 문제가 있는 것 같아 말씀 드려봅니다
124
작성자 없음
작성한 질문수 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
안녕하세요, 인프런 AI 인턴입니다. mhyim님.
JobQueue의 Push와 Execute 부분에 대한 문제를 추측해 보겠습니다. JobQueue의 구조 상 Push()와 Execute()는 보통 큐의 쓰레드 안전성을 유지하면서 작업을 적절히 처리하기 위한 요소입니다. 큐에 작업을 추가하기 위해서는 Push()를 사용하고, 큐에서 작업을 꺼내어 실행하기 위해 Execute()를 사용합니다.
보통 Push()가 이루어질 때, 해당 작업이 큐에 추가되며, 큐가 비어 있었던 경우 사용할 수 있도록 깨어나게 됩니다. 반면 Execute()에서는 큐에 들어있는 작업을 꺼내어 실행하며, 이 과정이 쓰레드 안전하게 이루어져야 하기 때문에 주의가 필요합니다.
문제가 담긴 코드는 Push() 호출 후 Execute()가 제대로 연계되지 않거나 두 함수가 적절히 동기화되지 않은 경우 발생할 수 있습니다. 예를 들어, 큐가 비어있거나 실행 중에 작업 요소들이 적절히 관리되지 않으면 문제가 발생할 수 있습니다.
관련된 기존의 질문과 답변을 확인해 보시기 바랍니다:
-
- 요약: JobTimer와 JobSerialize에서
Push()와Pop()은 lock이 잡혀 있지만Execute()에는 없어서 여러 쓰레드에서 실행될 경우의 우려와 해결책에 대해 다룹니다.
- 요약: JobTimer와 JobSerialize에서
-
- 요약: LCurrentJobQueue의 동작 및 여러 쓰레드에서의 접근 문제에 대해 설명합니다.
- 요약: LCurrentJobQueue의 동작 및 여러 쓰레드에서의 접근 문제에 대해 설명합니다.
위의 링크들은 JobQueue의 구조와 잠재적인 문제들에 대한 통찰을 제공할 것입니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
Memory Pool에서 오버플로우 질문입니다.
0
55
2
포토폴리오 및 진로 관련하여 고민입니다.
0
95
1
포토폴리오 관련 고민입니다.
0
49
1
실무에서도 alloc, 스마트포인터 등을 구현해서 쓰는지 궁금합니다.
0
74
2
성능 테스트 결과
0
97
2
게임 서버 Stateful, Stateless 진로 고민
0
113
1
WaitOnAddress와 Sleep의 차이 질문
0
78
1
궁금한거 있습니다.
0
78
2
JobTimer 구동 스레드
0
103
2
TryPop() 동작 관련 질문
0
78
1
로드맵 C#서버 C++서버 방향성 질문
0
142
2
스레드 id를 출력할떄 메인스레드 id도 출력되나요?
0
70
1
생명주기를 위한 의도적 복사
0
81
2
락프리의 실무에서 사용 질문
0
137
2
32bit threadID와 16비트 상위 WriteFlag에 대해
0
98
2
mutex와 sleep 차이점
0
114
1
실무에서는 어떠한 코드 스타일을 사용하는지 궁금합니다
0
149
2
Stomp Allocator의 Release함수에 대한 질문입니다.
0
91
1
공부법 관련해서
0
179
2
MakeShared 함수 관련
0
110
1
지금까지 서버코어에서 만든 내용에 대해 궁금한 점이 있어서 질문 드립니다.
0
140
2
운영체제관련 질문입니다
0
127
1
send하려는 데이터 크기가 크면 memcpy에서 문제가 발생할 것 같습니다.
0
114
2
메모리 풀 질문있습니다.
0
119
1





