프로그램/C++

클래스기반의 쓰레드 사용하기

네오류이 2021. 1. 13. 16:40
728x90
반응형

오늘은 쓰레드을 사용하는데 있어 일반적인 무한루프를 통해 프로세스를 처리하는 방식이 아닌

클래스기반하에 Cwnd 나 CDialog 기반하에 돌릴 수 있는 쓰레드를 만드는 방법에서 가장 심플하게 할 수 있는 방법을 소개하고 합니다.

 

CWinThread 을 통해서도 만드는 것도 있지만 오늘은 다른 방법으로 만들고자 합니다.

 

* 소스코드 (header)

#include "ProcessThread.h"

 

ProcessThread *mp_thread;

 

 

* 소스코드 (cpp)

mp_thread = NULL;

 

 

void CDlg::ThreadStart()

{

if(mp_thread) ThreadEnd();

 

mp_thread = (ProcessThread *)AfxBeginThread(RUNTIME_CLASS(ProcessThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED, NULL); //<-이 부분 추가

mp_thread->m_bAutoDelete = TRUE;        // 사실 이 부분 때문에 별도의 해제 없이 종료 해도 되지만 간혹 메모리 해제가 안되는 경우가 있다.

mp_thread->SetConfiguration(m_exe_str);    // 만들어진 함수.. 필요한 정보를 넣어 놓는다.

        mp_thread->ResumeThread();                // 시작...

}

 

// 사실 이 부분 때문에 별도의 해제 없이 종료 해도 되지만 간혹 메모리 해제가 안되는 경우가 있어 종료 시 한번 해준다.

void CDlg::ThreadEnd()

{

mp_thread->EndThreadProcess();

 

if(mp_thread){    // 종료를 해봐도 메모리가 남아있을 경우 대시도

DWORD dwExitCode;

mp_thread->PostThreadMessage(WM_QUIT, 0, 0);    /* UI 쓰레드 종료 메시지 전송 */

Sleep(100);

WaitForSingleObject(mp_thread->m_threadKillEvent, INFINITE);    // 종료가 될 때 까지 기다린다.

WaitForSingleObject(mp_thread->m_hThread, INFINITE);

GetExitCodeThread(mp_thread->m_hThread, &dwExitCode );

if( dwExitCode == STILL_ACTIVE){                                        // 그래도 살아 있으면 강제 종료

TerminateThread(mp_thread->m_hThread,0);

}

Sleep(10);

mp_thread = NULL;

 

}

}

 

void CDlg::ThreadEnd()

{

mp_thread->Test();

}

 

* 소스코드 (header) // 쓰레드

 

#include "ProcessWnd.h"

class ProcessThread : public CWinThread

{

ProcessWnd *mp_process_wnd;

...

}

 

 

* 소스코드 (cpp) // 쓰레드

 

ProcessThread::ProcessThread()

{

mp_process_wnd = NULL;

}

 

ProcessThread::~ProcessThread()

{

m_threadKillEvent.SetEvent(); // 스레드 종료 이벤트를 발생시킵니다

}

 

void ProcessThread::KillThreadEvent()

{

m_threadKillEvent.SetEvent(); // 스레드 종료 이벤트를 발생시킵니다

}

 

BOOL ProcessThread::InitInstance()

{

mp_desk_wnd = GetMainWnd();

mp_desk_wnd = NULL;

HWND dest_hwnd = ::GetDesktopWindow();

mp_desk_wnd = CWnd::FromHandle(dest_hwnd);    // 부모를 상황에 맞추어 실부모나 바탕화면 등등 설정하면 된다.

 

mp_process_wnd = NULL;

mp_process_wnd = new ProcessWnd();

if(mp_process_wnd){

mp_process_wnd->SetConfiguration(m_exe_str);

mp_process_wnd->Create(NULL,NULL, WS_CHILD, CRect(0,0,0,0), mp_desk_wnd, VAN_WND-1);

//mp_process_wnd->ModifyStyle(WS_CAPTION, WS_SYSMENU | WS_MINIMIZEBOX); // Event을 위한 것.,.

m_pMainWnd = mp_process_wnd;

}else{

TRACE0("Create ERR -.- !!!!");

}

 

return TRUE;

}

 

void ProcessThread::EndThreadProcess()

{

if(mp_process_wnd){

if(mp_process_wnd && ::IsWindow(mp_process_wnd->m_hWnd)){

mp_process_wnd->EndWndProcess();

if(mp_process_wnd && ::IsWindow(mp_process_wnd->m_hWnd)){

mp_process_wnd->DestroyWindow();

delete mp_process_wnd; mp_process_wnd = NULL;

}

}

//WaitForSingleObject(this->m_hThread, 1000);

}

}

 

 

 

위 내용은 중간중간 실제 제가 사용하는 부분을 추출하여 설명을 넣었습니다.

 

위 내용을 보시면 의미를 아실 수 있으며.. AfxBeginThread 이 함수를 RUNTIME_CLASS 방식으로 설정한다는 부분이 핵심입니다.

 

m_bAutoDelete 를 TRUE 로 하였기 때문에 사실 그냥 종료를 하면 쓰레드는 자동 해제가 됩니다. 하지만 간혹 안되는 경우가 있어 TerminateThread 를 해야 하는 경우도 존재하게 됩니다. 이 부분은 저도 왜 정상적으로 빨리 해제가 안되는지를 모르기 때문에 그냥 쓰고 있습니다.

 

많은 이용 바랍니다.

 

 

#c++#PostThreadMessage#WaitForSingleObject#스레드#쓰레드#클래스

728x90
반응형