#include "stdafx.h" #include "KThreadLoader.h" #include #include 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 ); } }