반응형

MFC에서의 멀티쓰레드(Multithread)

MFC에서의 Multithread
 
OS는 구분하지 않지만 MFC는 사용자 편의를 위하여 두 가지 형태로 지원한다.
 
1.     Worker thread
2.     User Interface thread


1. Work Thread

::AfxBeginThread() 함수를 이용


[설명]

메시지 루프를 포함하지 않고, 스레드 작업 중 입력을 허가하지 않는 스레드 형식

=> 스레드 작업 중 별도의 입력이 필요없을 때 사용


[사용법]

(스레드 시작)

1. CWinThread *pWorkThread = AfxBeginThread(ThreadFunc, &pParam);        

=>ThreadFunc가 전역함수인 경우 && Param값을 생성하여 넘겨줄 경우


2. CWinThread *pWorkThread = AfxBeginThread(ThreadFunc, this);  

=> ThreadFunc가 전역함수인 경우 && Param으로 이 스레드를 시작하는 클래스를 넘겨줄 경우


3. CWinThread *pWorkThread = AfxBeginThread(ThisClass::ThreadFunc, &pParam);  

=> ThreadFunc이 해당 클래스의 멤버함수인 경우 && Param값을 생성하여 넘겨줄 경우


4. CWinThread *pWorkThread = AfxBeginThread(ThisClass::ThreadFunc, this);  

=> ThreadFunc이 해당 클래스의 멤버함수인 경우 && Param으로 이 스레드를 해당 클래스를 넘겨줄 경우


(스레드 일시중지) - 주 Process에서 해야하며, 스레드 자신이 호출 불가.

pWorkThread->SuspendThread();


(스레드 재개)       - 주 Process에서 해야하며, 스레드 자신이 호출 불가.

pWorkThread->ResumeThread();


(스레드 동작 검사)

DWORD dwContextID; // 스레드 상태가 저장될 변수

GetExitCodeThread(pWorkThread->m_hThread, &dwContextID);


(Sleep())

ex) Sleep(2000); 
    - 제어권을 다른 Process에 넘겨 주게 된다. 
ex) Sleep(0);
    - 우선 순위가 높거나 같은 Process에 넘겨 주고 우선 순위가 높거나
      같은 Process가 없을 경우에는 아무 일도 생기지 않음.


(스레드 종료)

1. TreminateThread(pWorkThread->m_hThread, 0);

=> 스레드를 강제종료한다. 메모리 릭이 발생할 수 있으므로 추천하지 않음.


2. WaitForSingleObject(); - 무한

if ( ::WaitForSingleObject(pThread->m_hThread, INFINITE) )
{
       // 이곳은쓰레드가확실히종료된상태임
}

=> INFINITE 구문을 사용하여 스레드의 확실한 종료를 기다린다.

3. WaitForSingleObject(); - 시간지정

result = ::WaitForSingleObject(pThread->m_hThread, 1000);   // 1초기다림
if ( result == WAIT_OBJECT_0 )
{
       // 이곳은쓰레드가확실히종료된상태임
}
else if ( result == WAIT_TIMEOUT )
{
       // 1초가지나도쓰레드가종료되지않은상태
}

=>시간 지정을 하여 스레드 종료 시 먹통 예방.


(스레드 실행중인지 검사)

if ( ::WaitForSingleObject(pThread->m_hThread, 0 ) == WAIT_TIMEOUT )
{
       // pThread 실행중
}
else
{
       // pThread가실행중이아님
}


2. UI Thread


[설명]

메시지 루프를 포함하여 스레드 작업 중 사용자의 입력을 메시지 형태로 받아 처리하는 스레드 형식

=> 스레드 작업 중 별도의 입력이 필요할 때 사용


User Interface Thread
 
User interface thread는 그 자체로 윈도우와 메시지 루프를 가지고 있다.
 
class CUIThread : public CWinThread
{
       DECLARE_DYNCREATE(CUIThread)
 
public:
       virtual BOOL InitInstance();
};
 
이 User interface thread는 독자의 윈도우도 가질 수 있다. 일반적으로 전용 Dialog를 띄워
Thread를 처리하는 경우가 많으므로 이 User Dialog를 CMyDialog라고 이름 지었다고 가정하면
 
IMPLEMENT_DYNCREATE(CUIThread, CWinThread)
 
BOOL CUIThread::InitInstance()
{
       m_pMainWnd = new CMyDialog;
       m_pMainWnd->ShowWindow(SW_SHOW);
       m_pMainWnd->UpdateWindow();
       return TRUE;
}
 
와 같이 CMyDialog를 Thread로 띄울 수 있다. 그 다음
 
CWinThread *pThread = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
 
와 같이 하면 MFC가 알아서 CUIThread를 생성해서 그 포인터를 pThread에 넘겨 준다.
 
아래 예제에는 CMyDialog를 띄우고 주 Process는 사용자의
입력을 기다린다. Dialog의 Design 및 생성은 별도로 이야기하지 않는다. 아래 예제를 사용하기 위해서는
CMyDialog를 만들고 ID를 IDD_MYDIALOG라고 가정하면 CMyDialog의 생성자에 다음과 같이 추가해야 제대로 동작한다.
 
CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)
       : CDialog(CMyDialog::IDD, pParent)
{
       Create(IDD_MYDIALOG, NULL);
}
 
이제 완전히 별도로 동작하는(Thread로 동작하는) 윈도우를 하나 가지는 것이다. 만약 이것을 Dialog가 아닌
FrameWnd라고 해도 거의 똑같다. 다만 위에서도 언급했듯이 Thread를 이용할 때는 Dialog가 더 일반적일 것이다.
Worker thread에 비해 훨씬 더 많은 기능을 하는 것을 알게 되었을 것이다.
 
나머지 것들은 위의 Worker Thread에 있는 내용과 동일하다.
 
만약 여러 개의 CUIThread 를 여러 개 만들려고 한다면
 
CWinThread *pThread[5];
for ( int i = 0; i < 5; i++ )
       m_pThread[i] = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
 
와 같이 하면 5개의 Thread가 생성된다.
 
Program Execution Priority(프로그램 실행 우선순위)
 
Thread는 0~31까지의 priority를 가질 수 있다.
 
프로그램의 priority는
 
BOOL SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);
 
함수를 이용해서 조정할 수 있다. 첫 번째 인자 hProcess는 ::AfxGetInstanceHandle()로 얻으면 된다.
 
dwPriorityClass
Execution Priority
Description

DLE_PRIORITY_CLASS
CPU가 IDLE일 때만 사용 가능

ORMAL_PRIORITY_CLASS
보통

IGH_PRIORITY_CLASS
높은 우선 순위

EALTIME_PRIORITY_CLASS
최상위의 우선순위


Thread Execution Priority(쓰레드 실행 우선순위)
 
::AfxBeginThread() 함수의 nPriority를 통해서 설정하거나 CWinThread::SetThreadPriority 를 사용해 설정할 수 있다.
 
BOOL SetThreadPriority(HANDLE hThread, int nPriority);
 
nPriority
Execution Priority
Description

HREAD_PRIORITY_IDLE
REALTIME_PRIORITY_CLASS의 경우 16, 그 외에는 1

HREAD_PRIORITY_LOWEST
프로세스의 우선순위보다 2단계 낮은 우선순위를 가진다

HREAD_PRIORITY_BELOW_NORMAL
프로세스의 우선순위보다 1단계 낮은 우선순위를 가진다

HREAD_PRIORITY_NORMAL
프로세스의 우선순위가 같은 우선순위

HREAD_PRIORITY_ABOVE_NORMAL
프로세스의 우선순위보다 1단계 높은 우선순위를 가진다

HREAD_PRIORITY_HIGHEST
프로세스의 우선순위보다 2단계 높은 우선순위를 가진다

HREAD_PRIORITY_CRITICAL
REALTIME_PRIORITY_CLAS의 경우 31 그 외에는 16


프로그래머가 우선순위를 조정해도 Windows Scheduler가 상황에 맞게 조정하기 때문에 우선순위는
생각하고 조금 다를 수 있다.
 
Thread & Memory
 
각 Thread의 지역 변수는 모두 별도로 Stack을 만들고 Local Variable들을 관리하기 때문에 위의
 
CWinThread *pThread[5];
for ( int i = 0; i < 5; i++ )
       m_pThread[i] = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
 
와 같은 경우에도 각 Thread가 다른 Thread를 침범하는 일은 없다.
 
이 쯤에서 끝났나 싶겠지만… 아직 갈 길이 멀다.
Critical section, Mutex, Semaphore 같은 것들은 다음에…
 
Multithreading synchronization(멀티쓰레드의 동기화) => http://blog.naver.com/xtelite/50023359879
 
프로그램

Worker thread
 
#include "stdafx.h"
#include "console.h"
 
#include <iostream>
 
using namespace std;
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
// The one and only application object
CWinApp theApp;
 
using namespace std;
 
UINT ThreadPrintNum(LPVOID pParam);
 
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
       int nRetCode = 0;
 
       // initialize MFC and print and error on failure
       if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
       {
             _tprintf(_T("Fatal Error: MFC initialization failed\n"));
             return 1;
       }
 
       static BOOL bContinue = TRUE;
       CWinThread *pThread = ::AfxBeginThread(ThreadPrintNum, &bContinue);
 
       int count = 0;
       while ( count < 1000 )
       {
             count++;
       }
 
       Sleep(1000);
       pThread->SuspendThread();
       cout << "Thread suspended. Waiting for 2 seconds" << endl;
 
       Sleep(2000);
       cout << "Thread resumed" << endl;
       pThread->ResumeThread();
 
       cout << "Quit thread" << endl;
       bContinue = FALSE;
       Sleep(100);
 
       return nRetCode;
}
 
// 쓰레드함수
UINT ThreadPrintNum(LPVOID pParam)
{
       BOOL *pbContinue = (BOOL *)pParam;
       int count = 0;
       while ( *pbContinue )
       {
             count++;
       }
       cout << "Exit thread" << endl;
       return 0;
}
 
User interface thread
 
#include "stdafx.h"
#include "console.h"
 
#include "MyDialog.h"
 
#include <cstdlib>
 
using namespace std;
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
// The one and only application object
CWinApp theApp;
 
using namespace std;
 
class CUIThread : public CWinThread
{
       DECLARE_DYNCREATE(CUIThread)
 
public:
       virtual BOOL InitInstance();
};
 
IMPLEMENT_DYNCREATE(CUIThread, CWinThread)
 
BOOL CUIThread::InitInstance()
{
       m_pMainWnd = new CMyDialog;
       m_pMainWnd->ShowWindow(SW_SHOW);
       m_pMainWnd->UpdateWindow();
       return TRUE;
}
 
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
       int nRetCode = 0;
 
       // initialize MFC and print and error on failure
       if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
       {
             _tprintf(_T("Fatal Error: MFC initialization failed\n"));
             return 1;
       }
 
       CWinThread *pThread = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
       
       system("pause");
 
       return nRetCode;
}






출처 : "http://system.tistory.com/entry/멀티-쓰레딩"


반응형
Posted by tislqhf

블로그 이미지
개인적인 공부자료 정리하는 공간
tislqhf

태그목록

공지사항

Yesterday
Today
Total

달력

 « |  » 2025.2
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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함