Files
Leviathan/Client/Game/engine/Renderer/KThreadLoader.cpp
T
2026-06-01 12:46:52 +02:00

211 lines
4.9 KiB
C++

#include "stdafx.h"
#include "KThreadLoader.h"
#include <toolkit/khash.h>
#include <toolkit/ILock.h>
static std::vector< KThreadResource* > s_vPendingResource;
static XBossWorker s_Worker;
static XCriticalSection s_csThreadLoaderLock;
struct _STARTER
{
_STARTER()
{
s_Worker.StartThread( "KThreadLoader", 1 );
}
~_STARTER()
{
s_Worker.EndThread();
}
};
// 따로 StartThread/EndThread 처리를 해주기 귀찮아 하는듯 해서 삽입. 사실 이건 좋은 구현방식은 아니다.
static _STARTER _instance;
KThreadResource::KThreadResource() : m_bIsThreadLoadingComplete( false )
{
m_bIsLoadingRequested = false;
m_bIsLoading = false;
}
KThreadResource::~KThreadResource()
{
// 만약 현재 로딩 중이면 로딩이 끝날때까지 대기한다.
while( m_bIsLoading ) Sleep( 1 );
bool bNeedSleep = false;
while( true )
{
if( bNeedSleep ) Sleep( 10 );
THREAD_SYNCRONIZE( s_csThreadLoaderLock );
if( m_bIsLoading )
{
bNeedSleep = true;
continue;
}
bool bFoundPreRequestedLoading = false;
// 로딩 대기중이었다면 로딩 리스트에서 삭제한다.
std::vector< KThreadResource* >::iterator it;
for( it = s_vPendingResource.begin(); it != s_vPendingResource.end(); ++it )
{
// 선발주자가 있는지 확인
if( !bFoundPreRequestedLoading && (*it)->m_strResourceName == m_strResourceName ) bFoundPreRequestedLoading = true;
if( *it != this ) continue;
KThreadResource* p = (*it);
it = s_vPendingResource.erase( it );
p->m_bIsLoadingRequested = false;
break;
}
// 로딩요청이 없었던 객체이거나 이미 로딩이 끝난 객체이므로 별다른 처리가 필요 없음
if( it == s_vPendingResource.end() ) return;
// 내가 선발주자가 아니므로 역시 별다른 처리가 필요 없음.
if( bFoundPreRequestedLoading ) return;
// 나중 녀석들중 가장 앞에 있는 녀석에게 일을 인계한다.
for( ;it != s_vPendingResource.end(); ++it )
{
if( (*it)->m_strResourceName == m_strResourceName )
{
s_Worker.Push( (*it) );
break;
}
}
break;
}
}
// 그냥 쓰레드에 일만 던지는 녀석
bool KThreadResource::PendWorkToThreadPool( XBossWorker::XWorker * pWork )
{
return s_Worker.Push( pWork );
}
bool KThreadResource::onProcess( int nThreadNum )
{
// 로딩
m_bIsLoading = true;
bool bRtn = doLoading();
// 로딩후 처리
onThreadLoadingComplete();
return bRtn;
}
int KThreadResource::GetPendingWork()
{
THREAD_SYNCRONIZE( s_csThreadLoaderLock );
return (int)( s_Worker.GetPendingWorkCount() + s_Worker.GetWaitingWorkCount() );
}
void KThreadResource::CancelAllWork()
{
s_Worker.EndThread();
}
void KThreadResource::onThreadLoadingComplete()
{
THREAD_SYNCRONIZE( s_csThreadLoaderLock );
for( std::vector< KThreadResource* >::iterator it = s_vPendingResource.begin(); it != s_vPendingResource.end(); )
{
// 자신을 삭제한다
if( (*it) == this )
{
KThreadResource* p = (*it);
it = s_vPendingResource.erase( it );
p->m_bIsLoadingRequested = false;
continue;
}
// 같은 이름으로 로딩요청을 해놓은 리소스가 있다면 CopyFrom() 으로 복제를 할 수 있도록 해준다.
if( (*it)->m_strResourceName == m_strResourceName )
{
(*it)->CopyFrom( this );
KThreadResource* p = (*it);
it = s_vPendingResource.erase( it );
p->m_bIsLoadingRequested = false;
}
else
{
++it;
}
}
}
bool KThreadResource::CancelThreadLoading( KThreadResource * pWork )
{
THREAD_SYNCRONIZE( s_csThreadLoaderLock );
if( s_vPendingResource.empty() ) return false;
// 현재 로딩중인 녀석
if( pWork->m_bIsLoading ) return false;
// 리스트에서 지움
for( std::vector< KThreadResource* >::iterator it = s_vPendingResource.begin(); it != s_vPendingResource.end(); )
{
if( (*it) == pWork )
{
it = s_vPendingResource.erase( it );
pWork->m_bIsLoadingRequested = false;
break;
}
}
// 이미 같은 이름으로 대기중이었던 리소스가 있을는지를 찾아서 로딩 건다.
for( std::vector< KThreadResource* >::iterator it = s_vPendingResource.begin(); it != s_vPendingResource.end(); ++it )
{
if( (*it)->m_strResourceName == pWork->m_strResourceName )
{
s_Worker.Push( pWork );
break;
}
}
return true;
}
void KThreadResource::StartThreadLoading( KThreadResource * pWork, const char *szName )
{
THREAD_SYNCRONIZE( s_csThreadLoaderLock );
pWork->m_strResourceName = szName;
// 이미 같은 이름으로 로딩중인 리소스가 있을는지를 찾는다.
bool bAlreadyPendLoading = false;
for( std::vector< KThreadResource* >::iterator it = s_vPendingResource.begin(); it != s_vPendingResource.end(); ++it )
{
if( (*it)->m_strResourceName == szName )
{
bAlreadyPendLoading = true;
break;
}
}
pWork->m_bIsLoadingRequested = true;
// 로딩 리스트에 삽입한다.
s_vPendingResource.push_back( pWork );
// 새로운 리소스이니 로딩을 건다.
if( !bAlreadyPendLoading )
{
s_Worker.Push( pWork );
}
}