본문 바로가기
Programming Language/C++,MFC

MFC 작업자 쓰레드(Worker Thread) 사용법

by 민트초코맛꼬깔콘 2014. 10. 20.

출처 : http://blog.daum.net/riversnails/8000679

--------------------------------------------

// Mydlg.h 파일

// 쓰레드 함수용으로 사용될 구조체 변수 선언, 쓰레드 함수는 4Byte void형 포인터 밖에 파라미터로 줄 수 없기에 여러가지 값을 넘기기 위해 구조체의 포인터를 넘겨 주기 위함이다.

typedef struct tagThreadParam

{

CWnd *pWnd; // CMydlg 포인터를 담을 변수

BOOL *pDo; // CMydlg의 쓰레드 정지용 플래그를 담을 포인터 변수

// 그 밖에 필요한 것을 이 구조체에 선언하면 된다.

} THREADPARAM;


class CMydlg : public CDialog

{

BOOL m_bDo; // 쓰레드 정지용 플래그

CWinThread *m_pThread; // 쓰레드 포인터


static UINT MyThreadFunc(LPVOID pThreadParam); // 쓰레드 함수 : 전역함수로 할 수도 있지만, 클래스 내 함수로 할 경우는 static을 붙여야 한다. 쓰레드 함수는 반드시 이 형태로 만들어야 한다. 약속이다. 


void StartThread(); // 쓰레드를 시작 시킬 사용자 정의 함수

void StopThread(); // 쓰레드를 정지 시킬 사용자 정의 함수

void MyWorkFunc(); // 쓰레드 함수 내에서 실행할 함수


}


// Mydlg.cpp 파일


UINT CMydlg::MyThreadFunc(LPVOID pThreadParam)

{

 // 넘어 온 파라미터가 void 형 포인터 이므로 THREADPARAM 형 포인터로 반드시 캐스팅해야 한다.

THREADPARAM *pParam = (THREADPARAM *)pThreadParam;


CMydlg *pMydlg = (CMydlg *)pParam->pWnd; // 이것 또한 캐스팅 해야 한다.

BOOL *pDo = pParam->pDo; // 이것은 같은 타입이므로 캐스팅 필요 없다.


// 변수에 필요한 포인터를 모두 담았으니 동적 생성된 pParam을 동적으로(?) 삭제해야 메모리 누수가 없다.

delete pParam;


// *pDo가 TRUE일 동안 쓰레드가 작업을 한다.

while ( *pDo ) // 여기에서 *pDo대신에 pMydlg->m_bDo 해도 된다. 예를 들기 위해 임의로 사용한 것일 뿐

{

pMydlg->MyWorkFunc(); // 원하는 작업을 한다.

// 기타 원하는 작업을 이곳에 넣으면 된다.

}


return 0; // 반드시 리턴을 해야 한다. 0으로 리턴 하는 것은 일종의 약속이다.

}


void CMydlg::StartThread()

{

// 쓰레드함수의 파라미터로 쓸 구조체를 동적으로 생성한다.

THREADPARAM *pThreadParam = new THREADPARAM;

pThreadParam->pWnd = this; // 여기서 this는 CMydlg 객체를 의미한다.

pThreadParam->pDo = &m_bDo; // 플래그 포인터를 담는다.


// AfxBeginThread 함수로 쓰레드가 생성되어 실행된다.

m_pThread = AfxBeginThread(MyThreadFunc, pThreadParam);

}


void CMydlg::StopThread()

{

m_bDo = FALSE; // 쓰레드 정지 시키기 위해 FALSE를 입력한다.


Sleep(100); // 이것은 매우 중요하다. 이걸 하지 않으면 쓰레드가 작동이 잘 안될 수가 있다. 쓰레드에 체크할 여유를 준다고 생각하면 된다.


// 정지용 플래그 값을 입력했으니 아래 함수로 쓰레드가 끝날 때까지 기다려 준다.

if ( ::WaitForSingleObject(m_pThread->m_hThread, INFINITE ) // INFINITE는 무한정 기다려 준다는 의미다.

{

// 쓰레드가 끝나면 이 속으로 들어온다.

m_pThread = NULL; // 죽은 쓰레드니 비우자.

// 쓰레드 끝나고 할 것들을 여기에 넣으면 된다.

}

}