211 lines
4.9 KiB
C++
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 );
|
|
}
|
|
} |