티스토리 뷰

[원본 - 2013년 이글루스]


MFC없이 Win32 API 만을 이용해 Thread 프로그래밍을 하던 중

자바나 C#의 Thread 클래스처럼 class화 해서 사용할 수 있으면 좋겠다고 생각해서 대충 생각나는대로 디자인을 해봤다

일단 간단한 Thread 프로그래밍에는 그럭저럭 만족스러운 모습을 보여주었다

#ifndef _BASIC_THREAD_H_
#define _BASIC_THREAD_H_

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

/*=======================================================================
** File          : BasicThread.h
** Desc          : 기본적인 Thread Class
** Author        : Jin-Gyu Choi
** Create        : 2013.03.28
** Last Modify   : 2013.03.28
========================================================================*/

class BasicThread
{
protected:
    HANDLE m_hThread;        // Window Thread Handle
    DWORD  m_nThreadID;      // Window Thread ID
    
private:
    BasicThread( const BasicThread& bt ) {}                 // 해당 Thread의 복제를 막는다
    BasicThread& operator = ( const BasicThread& bt ) {}    // 해당 Thread의 복제를 막는다
    
    static DWORD WINAPI StaticThreadStart( LPVOID lpParam ) // 실제 Thread의 시작부분
    {
        BasicThread* pThread = (BasicThread*)lpParam;
        return pThread->Run();
    }
    
protected:
    virtual DWORD Run(void) = 0;    // Protected로 사용자가 직접 호출하는 것을 막음
    
public:
    BasicThread() : m_hThread( NULL ), m_nThreadID( 0 )
    {
    }
    
    virtual ~BasicThread()
    {
        if( m_hThread ) CloseHandle( m_hThread );
    }
    
public:
    //----------------------------------------------------------------
    // public functions
    //----------------------------------------------------------------
    bool Start()    // Thread 시작
    {
        if( m_hThread ) // 이미 Thread가 생성되어 있는 경우
        {
            if( WaitForSingleObject( m_hThread, 0 ) == WAIT_TIMEOUT ) { // Thread Still Running
                return false;    // Start 거부
            }
            CloseHandle( m_hThread );
        }
        
        // Thread 생성
        m_hThread = CreateThread(
                     NULL,            // default security attributes
                     0,               // default stack size
                     (LPTHREAD_START_ROUTINE)BasicThread::StaticThreadStart,
                     this,            // thread function argument = this class
                     0,               // default creation flags
                     &m_nThreadID     // receive thread identifier
                 );
        
        if( m_hThread != NULL ) return true;
        
        return false;
    }
    
    void Stop()    // Thread 강제 종료 - 비추!!
    {
        if( this->IsRunning() )    {
            // 강제 Terminate이므로 정상적인 자원 해제를 기대할 수 없음
            // 공유자원 등을 물고 있을 경우 deadlock 등의 위험이 있을 수 있음
            ::TerminateThread( m_hThread, -1 );
        }
        
        if( m_hThread ){
            CloseHandle( m_hThread );
            m_hThread = NULL;
        }
    }
    
public:
    //----------------------------------------------------------------
    // inline functions
    //----------------------------------------------------------------
    
    // Getter
    inline HANDLE GetThreadHandle() { return m_hThread; }
    inline DWORD GetThreadID() { return m_nThreadID; }
    
    // Status
    inline bool IsRunning()
    {
        if( m_hThread ){
            DWORD dwExitCode = 0;
            ::GetExitCodeThread( m_hThread, &dwExitCode );
            if( dwExitCode == STILL_ACTIVE ) return true;
        }
        return false;
    }
    
    // Join - Wait For Thread Done
    inline void Join()
    {
        ::WaitForSingleObject( m_hThread, INFINITE );
    }
    
    // Yeild - Yeild Execution to Another Thread
    inline BOOL Yeild()
    {
        return ::SwitchToThread();
    }
    
    // Sleep - Suspends the execution of the current thread until the time-out interval elapses
    inline void Sleep( DWORD dsMilliiseconds )
    {
        ::Sleep( dsMilliiseconds );
    }
    
    // Suspend - Suspend Thread
    inline DWORD Suspend()
    {
        return ::SuspendThread( m_hThread );
    }
    
    // Resume - Resume Thread
    inline DWORD Resume()
    {
        return ::ResumeThread( m_hThread );
    }
    
};

#endif

BasicThread 클래스 그 자체로는 Run이 정의되어 있지 않기 때문에 그대로 사용하는 것은 안되고

실제로 사용하기 위해서는 BasicThread 클래스를 상속받아 Run() 함수를 구현해서 사용하면 된다

대략 사용한다면 이런 느낌???

물론 원한다면 맴버변수, static 변수 모두 사용 가능하다

#include <stdio.h>
#include "BasicThread.h"

class TestThread : public BasicThread
{
protected:
    DWORD Run(void)
    {
        printf("Thread %d Start\n", GetThreadID());
        
        for( int i = 0; i < 5; i++ )
        {
            printf("Thread %d : Count %d\n", GetThreadID(), i);
            this->Sleep( 1000 );
        }
        
        printf("Thread %d End\n", GetThreadID());
        
        return 0;
    }
};

int main(void)
{
    TestThread* pThread[5];
    
    for( int i = 0 ; i < 5; i++ )
    {
        pThread[i] = new TestThread();
        pThread[i]->Start();
    }
    
    for( int i = 0 ; i < 5; i++ )
    {
        pThread[i]->Join();
        delete pThread[i];
    }
    
    return 0;
}


댓글
최근에 올라온 글
Total
Today
Yesterday
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31