/////////////////////////////////////////////////////////////////// // INCLUDE /////////////////////////////////////////////////////////////////// #include "STDAFX.H" #include "THREAD.H" /////////////////////////////////////////////////////////////////// // IMPLEMENTATION /////////////////////////////////////////////////////////////////// //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::CThread //*--------------------------------------------------------------- // DESC : »ý¼ºÀÚ // PARM : N/A // RETV : N/A // PRGM : B4nFter //*--------------------------------------------------------------- CThread::CThread() { Reset(); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::~CThread //*--------------------------------------------------------------- // DESC : ¼Ò¸êÀÚ // PARM : N/A // RETV : N/A // PRGM : B4nFter //*--------------------------------------------------------------- CThread::~CThread() { } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::Start //*--------------------------------------------------------------- // DESC : ½º·¹µå¸¦ ½ÇÇà // PARM : 1 . lpfnThreadProc - ½º·¹µå ÇÁ·Î½ÃÀú Æ÷ÀÎÅÍ // 2 . lpParam - ½º·¹µå¿¡ ÁöÁ¤ÇÒ ÀÎÀÚ°ª (±âº»°ª NULL) // 3 . lpszName - ½º·¹µå À̸§ (±âº»°ª NULL) // 4 . uStackSize - ½º·¹µå ½ºÅÃÅ©±â (±âº»°ª 0 ¡æ 1MB) // 5 . bSuspend - »ý¼º Á÷ÈÄ Áö¿¬¿©ºÎ (±âº»°ª FALSE) // 6 . bAutoEnd - Á¾·á ½Ã ÀÚµ¿ ÀÚ¿øÇØÁ¦¸¦ ÇÒÁö ¿©ºÎ (±âº»°ª TRUE, FALSE ÀÏ °æ¿ì »ç¿ëÀÚ°¡ Á÷Á¢ CThread::End() È£Ãâ) // 7 . m_lpPrepProc - ½º·¹µå ½ÃÀÛ ½Ã ½ÇÇàµÇ´Â ·çƾ (±âº»°ª NULL) // 8 . m_lpPostProc - ½º·¹µå Á¾·á ½Ã ½ÇÇàµÇ´Â ·çƾ (±âº»°ª NULL) // 9 . m_lpPrepProcParam - ½º·¹µå ½ÃÀÛ ·çƾ¿¡ Àü´ÞµÇ´Â ÀÎÀÚ (±âº»°ª NULL) // 10 . m_lpPostProcParam - ½º·¹µå Á¾·á ·çƾ¿¡ Àü´ÞµÇ´Â ÀÎÀÚ (±âº»°ª NULL) // RETV : TRUE - ¼º°ø / FALSE - ½ÇÆÐ // PRGM : B4nFter //*--------------------------------------------------------------- BOOL CThread::Start( LPFN_THREAD_PROC lpfnThreadProc, LPVOID lpParam, LPCTSTR lpszName, UINT uStackSize, BOOL bSuspend, BOOL bAutoEnd, LPFN_PREP_PROC lpfnPrepProc, LPFN_POST_PROC lpfnPostProc, LPVOID lpPrepProcParam, LPVOID lpPostProcParam ) { if (m_hHandle) { return FALSE; } if (!lpfnThreadProc) { return FALSE; } m_lpfnThreadProc = lpfnThreadProc; m_lpParam = lpParam; m_bAutoEnd = bAutoEnd; m_lpfnPrepProc = lpfnPrepProc; m_lpfnPostProc = lpfnPostProc; m_lpPrepProcParam = lpPrepProcParam; m_lpPostProcParam = lpPostProcParam; if (lpszName) { STRNCPY(m_szName, lpszName, COUNT_OF(m_szName)); } m_hHandle = (HANDLE)::_beginthreadex(NULL, uStackSize, ThreadProc, (LPVOID)(this), (bSuspend)?(CREATE_SUSPENDED):(0), &m_uId); if (!m_hHandle) { return FALSE; } return TRUE; } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::Reset //*--------------------------------------------------------------- // DESC : ½º·¹µå °´Ã¼ÀÇ Á¤º¸¸¦ ¸®¼Â // PARM : N/A // RETV : N/A // PRGM : B4nFter //*--------------------------------------------------------------- VOID CThread::End() { if (DF_MEMSTATE_DDDD == (DWORD_PTR)m_hHandle) { // HEAP ¿¡¼­ ÇØÁ¦µÈ °æ¿ì º°µµ Á¾·á ¾ø¾î¾ß ÇÔ return; } if (m_hHandle) { DWORD dwExitCode = 0; ::GetExitCodeThread(m_hHandle, &dwExitCode); if (STILL_ACTIVE == dwExitCode) { // ½º·¹µå Á¾·á ½Ã¿¡´Â TLS¸¦ ¸í½ÃÀûÀ¸·Î ÇØÁ¦ÇÏÁö ¾ÊÀ½ (STL ÀÚ¿øÀÌ ¹Ì¸® ÇØÁ¦µÊÀ¸·Î ÀÎÇÑ Access Violation ¿¹¿Ü¸¦ ÇÇÇϱâ À§ÇÔ, ½Ã½ºÅÛ¿¡ ÇØÁ¦ ¸Ã±è?) std::set::iterator it = m_setTlsValue.begin(); for (; it != m_setTlsValue.end() ; ++it) { if ((*it) != TLS_OUT_OF_INDEXES) { ::TlsFree(*it); } } m_setTlsValue.clear(); } ::CloseHandle(m_hHandle); } Reset(); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::Reset //*--------------------------------------------------------------- // DESC : ½º·¹µå °´Ã¼ÀÇ Á¤º¸¸¦ ¸®¼Â // PARM : N/A // RETV : N/A // PRGM : B4nFter //*--------------------------------------------------------------- VOID CThread::Reset() { m_hHandle = NULL; m_uId = 0; m_lpfnThreadProc = NULL; m_lpParam = NULL; m_szName[0] = _T('\0'); m_bAutoEnd = TRUE; m_lpfnPrepProc = NULL; m_lpfnPostProc = NULL; m_lpPrepProcParam = NULL; m_lpPostProcParam = NULL; } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::ThreadProc //*--------------------------------------------------------------- // DESC : ½º·¹µåÀÇ ¸ÞÀÎ ½ÇÇà·çƾ, CThread:m_lpfnThreadProc ¸¦ ½ÇÇà // PARM : 1 . lpParam - ½º·¹µå¿¡ ÁöÁ¤ÇÒ ÀÎÀÚ°ª // RETV : ½º·¹µåÀÇ Á¾·áÄÚµå // PRGM : B4nFter //*--------------------------------------------------------------- UINT __stdcall CThread::ThreadProc(LPVOID lpParam) { CThread* lpThread = (CThread*)lpParam; if (!lpThread || !lpThread->m_lpfnThreadProc) { return 0; } if ((DF_MEMSTATE_DDDD != ((DWORD_PTR)(lpThread->m_hHandle))) && ::_tcsncmp(lpThread->m_szName, _T(""), COUNT_OF(lpThread->m_szName)) ) { lpThread->SetName(lpThread->m_szName); } if ((DF_MEMSTATE_DDDD != ((DWORD_PTR)(lpThread->m_hHandle))) && lpThread->GetPrepProc() ) { lpThread->GetPrepProc()(lpThread->GetPrepProcParam()); } UINT iRetVal = 0; if ((DF_MEMSTATE_DDDD != ((DWORD_PTR)(lpThread->m_hHandle))) && lpThread->m_lpfnThreadProc ) { iRetVal = lpThread->m_lpfnThreadProc(lpThread->GetParam()); } if ((DF_MEMSTATE_DDDD != ((DWORD_PTR)(lpThread->m_hHandle))) && lpThread->GetPostProc() ) { lpThread->GetPostProc()(lpThread->GetPostProcParam()); } if ((DF_MEMSTATE_DDDD != ((DWORD_PTR)(lpThread->m_hHandle))) && lpThread->IsAutoEnd() ) { lpThread->End(); } return iRetVal; } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::SetName //*--------------------------------------------------------------- // DESC : ÇöÀç ½º·¹µå À̸§À» ÁöÁ¤ // PARM : 1 . lpszName - ½º·¹µå À̸§ // RETV : N/A // PRGM : B4nFter // P.S.> // - ½º·¹µå¸¦ »ý¼ºÇÑ ÈÄ ÁöÁ¤ÇØ¾ß ÇÔ (CThread::Start() ¿¡¼­ À̸§ ÀúÀå, CThread::ThreadProc() ¿¡¼­ À̸§ ÁöÁ¤) // - ½º·¹µå À̸§ Ç¥½Ã´Â Debug ¡æ Thread ´ëȭâ¿¡¼­ È®ÀÎ °¡´É //*--------------------------------------------------------------- VOID CThread::SetName(LPCTSTR lpszName) { SetName(lpszName, (DWORD)(-1)); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::SetName //*--------------------------------------------------------------- // DESC : ƯÁ¤ ½º·¹µå À̸§À» ÁöÁ¤ // PARM : 1 . lpszName - ½º·¹µå À̸§ // 2 . pThreadID - ½º·¹µå ID // RETV : N/A // PRGM : B4nFter // P.S.> // - ½º·¹µå¸¦ »ý¼ºÇÑ ÈÄ ÁöÁ¤ÇØ¾ß ÇÔ (CThread::Start() ¿¡¼­ À̸§ ÀúÀå, CThread::ThreadProc() ¿¡¼­ À̸§ ÁöÁ¤) // - ½º·¹µå À̸§ Ç¥½Ã´Â Debug ¡æ Thread ´ëȭâ¿¡¼­ È®ÀÎ °¡´É //*--------------------------------------------------------------- VOID CThread::SetName(LPCTSTR lpszName, DWORD pThreadID) { if (!lpszName) { BASE_RETURN_NONE; } USES_CONVERSION; THREADNAMEINFO stThreadNameInfo; stThreadNameInfo.dwType = 0x1000; stThreadNameInfo.szName = T2CA(lpszName); stThreadNameInfo.dwThreadID = pThreadID; stThreadNameInfo.dwFlags = 0; __try { ::RaiseException(0x406D1388, 0, sizeof(THREADNAMEINFO)/sizeof(DWORD), (const ULONG_PTR*)&stThreadNameInfo); } __except(EXCEPTION_CONTINUE_EXECUTION) { NULL; } } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::GetName //*--------------------------------------------------------------- // DESC : ½º·¹µå À̸§À» ¾ò¾î¿È // PARM : N/A // RETV : ½º·¹µå À̸§ // PRGM : B4nFter //*--------------------------------------------------------------- LPCTSTR CThread::GetName() const { return m_szName; } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::Suspend //*--------------------------------------------------------------- // DESC : ½º·¹µåÀÇ Suspend »óŸ¦ ÇØÁ¦ // PARM : N/A // RETV : ¼º°ø:previous suspend count / ½ÇÆÐ:0xFFFFFFFF // PRGM : B4nFter //*--------------------------------------------------------------- DWORD CThread::Suspend() { if (!m_hHandle) { return (DWORD)(0xFFFFFFFF); } return ::SuspendThread(m_hHandle); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::Resume //*--------------------------------------------------------------- // DESC : ½º·¹µåÀÇ Suspend »óŸ¦ ÇØÁ¦ // PARM : N/A // RETV : ¼º°ø:previous suspend count / ½ÇÆÐ:0xFFFFFFFF // PRGM : B4nFter //*--------------------------------------------------------------- DWORD CThread::Resume() { if (!m_hHandle) { return (DWORD)(0xFFFFFFFF); } return ::ResumeThread(m_hHandle); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::Terminate //*--------------------------------------------------------------- // DESC : ½º·¹µå¸¦ °­Á¦ Á¾·áÇÔ // PARM : 1 . dwExitCode - Thread Á¾·áÄÚµå // RETV : TRUE - ¼º°ø / FALSE - ½ÇÆÐ // PRGM : B4nFter //*--------------------------------------------------------------- BOOL CThread::Terminate(DWORD dwExitCode) { if (!m_hHandle) { return FALSE; } return ::TerminateThread(m_hHandle, dwExitCode); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::SetPriority //*--------------------------------------------------------------- // DESC : ½º·¹µå ¿ì¼±¼øÀ§¸¦ ÁöÁ¤ // PARM : 1 . iPriority - ¿ì¼±¼øÀ§ (1~31±îÁö, ¹øÈ£°¡ ³ôÀ» ¼ö·Ï ¿ì¼±¼øÀ§ ³ôÀ½) // RETV : TRUE - ¼º°ø / FALSE - ½ÇÆÐ // PRGM : B4nFter // P.S.> // - MSDN ÀÇ Scheduling Priorities Âü°í //*--------------------------------------------------------------- BOOL CThread::SetPriority(INT iPriority) { if (!m_hHandle) { return FALSE; } return ::SetThreadPriority(m_hHandle, iPriority); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::SetAffinity //*--------------------------------------------------------------- // DESC : ½º·¹µå ģȭµµ¸¦ ÁöÁ¤ // PARM : 1 . dwMask - ģȭµµ ¸¶½ºÅ© (ģȭµµ¸¦ ¼³Á¤ÇϰíÀÚ ÇÏ´Â CPU¼ø¼­¿¡ ÇØ´çÇÏ´Â ºñÆ®µéÀ» 1·Î ¼Â) // RETV : TRUE - ¼º°ø / FALSE - ½ÇÆÐ // PRGM : B4nFter //*--------------------------------------------------------------- BOOL CThread::SetAffinity(DWORD dwMask) { if (!m_hHandle) { return FALSE; } return (BOOL)::SetThreadAffinityMask(m_hHandle, dwMask); } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::GetTlsIndex //*--------------------------------------------------------------- // DESC : Thread Local Storage ¸¦ ÇÒ´çÇϰí ÇÒ´çµÈ °ø°£ÀÇ À妽º¸¦ °¡Á®¿È // PARM : N/A // RETV : ÇÒ´çµÈ TLSÀÇ À妽º // PRGM : B4nFter //*--------------------------------------------------------------- DWORD CThread::GetTlsIndex() { DWORD dwTlsIndex = ::TlsAlloc(); if (dwTlsIndex != TLS_OUT_OF_INDEXES) { m_setTlsValue.insert(dwTlsIndex); } return dwTlsIndex; } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::SetTlsValue //*--------------------------------------------------------------- // DESC : Thread Local Storage ÀÇ Æ¯Á¤ À妽º¿¡ °ªÀ» ÁöÁ¤ // PARM : 1 . dwTlsIndex - TLS À妽º // 2 . lpTlsValue - TLS À妽º °ø°£¿¡ ÁöÁ¤ÇÒ °ª // RETV : TRUE - ¼º°ø / FALSE - ½ÇÆÐ // PRGM : B4nFter //*--------------------------------------------------------------- BOOL CThread::SetTlsValue(DWORD dwTlsIndex, LPVOID lpTlsValue) { std::set::iterator it = m_setTlsValue.find(dwTlsIndex); if (it != m_setTlsValue.end()) { return ::TlsSetValue(dwTlsIndex, lpTlsValue); } return FALSE; } //*--------------------------------------------------------------- // TYPE : FUNCTION // NAME : CThread::FreeTlsIndex //*--------------------------------------------------------------- // DESC : Thread Local Storage ÀÇ Æ¯Á¤ À妽º¸¦ ÇØÁ¦ // PARM : 1 . dwTlsIndex - TLS À妽º // RETV : N/A // PRGM : B4nFter //*--------------------------------------------------------------- VOID CThread::FreeTlsIndex(DWORD dwTlsIndex) { if (dwTlsIndex == TLS_OUT_OF_INDEXES) { return; } std::set::iterator it = m_setTlsValue.find(dwTlsIndex); if (it != m_setTlsValue.end()) { m_setTlsValue.erase(dwTlsIndex); } }