MFC 스레드 클래스 사용

- 출처 : http://jbjempire.egloos.com/page/3


MFC 라이브러리에서는 CWinThread 클래스를 제공한다. MFC에서 유일한 스레드 클래스이며, MFC 어플리케이션의 모든 스레드는 CWinThread 로 대표된다.

MFC 스레드는 CWinThread 클래스의 용도를 크게 다음 2가지로 구분한다.
1. 작업자 스레드
2. 사용자 인터페이스 스레드
WIN32에서는 이 두 가지를 구분하지 않는다.


작업자 스레드
계산이나 입출력과 같이 사용자의 입력을 필요로 하지 않는 작업에 사용되는 스레드를 말한다.


사용자 인터페이스 스레드
사용자의 입력을 받거나, 사용자에 의해서 발생되는 이벤트를 처리할 목적의 스레드에 사용된다. 다시 말하면, 스레드 내부에 메시지 또는 이벤트를 처리할 수 있는 루틴을 포함하고 있다는 뜻이다. CWinThread 클래스는 메시지 펌프를 제공하여 사용자 입력 또는 이벤트를 처리할 수 있도록 하였다. 대표적으로 CWinApp 가 메시지 펌프를 사용한 사용자 인터페이스 스레드의 예이다.

사용자로부터의 입력 또는 이벤트에 따른 처리가 가능한 윈도우를 갖는 스레드를 말한다. 이러한 처리는 윈도우, 메시지펌프, 메시지큐, 메시지 프로시저(이벤트 핸들러)가 스레드 내에 존재해야 한다는 뜻이다.

AfxBeginThread, AfxEndThread

일반적으로는 객체를 만들기 위해 new를 사용하지만, CWinThread는 MFC 전역함수 AfxBeginThread를 호출하여 생성한다. 작업자 스레드와 사용자 인터페이스 스레드를 생성할 수 있도록 두 가지 형태의 AfxBeginThread() 를 제공한다.


MFC 작업자 스레드 생성
CWinThread* AfxBeginThread(
ㅁㅁAFX_THREADPROC pfnThreadProc,                        // 실행시킬 함수포인터
ㅁㅁLPVOID pParam,                                                     // 함수에 전달할 포인터
ㅁㅁint nPriority = THREAD_PRIORITY_NORMAL,            // 스레드 우선순위등급
ㅁㅁUINT nStackSize = 0,                                              // 초기 스택 크기
ㅁㅁDWORd dwCreateFlags = 0,                                   // 생성옵션
ㅁㅁLPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL // 보안속성
)

AfxBeginThread() 는, 함수명(포인터)과 전달될 파라미터로 호출될 경우, 코드상에서 보면, 단지 함수가 스레드로 실행되는 것처럼 보인다.

AfxBeginThread() 는, 내부적으로는 CWinThread 클래스 객체를 생성하여 사용할 수도 있고, CWinThread 클래스에서 파생된 클래스를 직접 작성하여 사용할 수도 있다. 이때 스레드 함수는 해당 스레드 클래스의 정적 멤버함수로 작성하여 사용한다(물론 다른 방법도 있지만 권장하지 않는다)


사용자 인터페이스 스레드 생성

CWinThread* AfxBeginThread(
ㅁㅁCRuntimeClass* pThreadClass,
ㅁㅁint nPriority = THREAD_PRIORITY_NORMAL,
ㅁㅁUINT nStackSize = 0,
ㅁㅁDWORd dwCreateFlags = 0,
ㅁㅍLPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL  // 보안속성
)

1. CWinThread 객체 생성 (CWinThread::CWinThread)
2. 스레드 루틴 실행 (CWinThread::CreateObject)
3. 스레드 우선 등급 설정 (CWinThread::SetThreadPriority)
4. 스레드 재개 (CWinThread::ResumeThread, 옵션에 따라)


CWinThread 클래스

CWinThread 클래스에서 ‘작업자 스레드’와 ‘사용자 인터페이스 스레드’를 구분하는 기준
은 스레드 함수 포인터의 유무에 의해서 결정된다. 스레드 함수 포인터를 생성자에서 초기화하지 않는 사용자 인터페이스 스레드는 Run() 함수를 사용한다.


작업자 스레드 용

CWinThread::CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam)
{
ㅁㅁm_pfnThreadProc = pfnThreadProc;// 추가로 실행할 스레드 함수포인터
}


사용자 인터페이스 스레드 용

CWinThread::CWinThread()
{
ㅁㅁm_pThreadParams = NULL;// 스레드 함수포인터가 NULL
}

객체가 생성된 이후 CWinThread::CreateThread() 를 호출한다. 이 멤버함수는 _beginthreadex() 를 호출하면서 _AfxThreadEntry() 전역함수를 스레드로 실행한다.

_beginthreadex(
ㅁㅁlpSecurityAttrs,
ㅁㅁnStackSize,
ㅁㅁ&_AfxThreadEntry,
ㅁㅁ&startup,
ㅁㅁdwCreateFlags | CREATE_SUSPENDED,
ㅁㅁ(UINT*)&m_nThreadID
);

MFC로 생성되는 모든 추가 스레드의 실행 루틴은 _AfxThreadEntry 이다. _AfxThreadEntry는 CWinThread 의 함수포인터 pThread->m_pfnThreadProc의 유무를 판단하여 작업자 스레드와 사용자 인터페이스 스레드를 구분하여 실행한다.

AfxThreadEntry() 에 의해 구분된
1. 작업자 스레드는 해당 ‘스레드 함수’ 를 호출한다.
2. 사용자 인터페이스 스레드는 다음 순서로 호출된다.
A. CWinThread::InitInstance()
B. CWinThread::Run()
C. CWinThread::ExitInstance()

Windows 운영체제는 스레드 단위로 메시지 큐를 제공한다는 것이다. 이를 이용한 것이 바로 사용자 인터페이스 스레드이다.

 

 

WIN32 API

 

CreateThread

ExitThread

C 런타임 라이브러리

 

_beginthread/_beginthreadex

_endthread/_endthreadex

C++ 스레드 클래스를 제작하여 이용

Static CMyThread::ThreadFunc

MFC가 제공하는 CWinThread

 

AfxBeginThread

AfxEndThread

 

Posted by six605
,