1. 단일문서 프로젝트 생성(문서뷰아키텍트 체크 해제)
2. MFC클래스 추가(CUIThr), 기본클래스를 CWinThread로 함
3. 리소스 뷰-메뉴-IDR_MAINFRAME열어 메뉴추가 할 수 있음
4. 오른쪽 버튼 클릭하여 ID편집 할 수 있음
5. 마우스 오른쪽버튼 클릭-이벤트 처리기 추가(이 버튼을 클릭했을 때 일어나는 일)
메시지형식(COMMAND), 클래스 목록(CMainFrame)
→ MainFrm.cpp클래스가 추가되고 OnMenuCreateuithread()함수가 생성됨
6. 다른 헤더파일들이 인클루드 되어 있는 MainFrm.cpp에 "UIThr.h" 인클루드 해준다.
#include "UIThr.h"
7. MainFrm.cpp안의 OnMenuCreateuithread()함수 내에 스레드를 만들어 준다.(코드 작성)
void CMainFrame::OnMenuCreateuithread()
{
AfxBeginThread(RUNTIME_CLASS(CUIThr));
} // 여기까지 하면 스레드가 실행됨
8. UIThr.cpp안의 InitInstance()함수에 ...............을 하는 코드를 작성한다.
BOOL CUIThr::InitInstance()
{
CMainFrame* pFrame = new CMainFrame;
if(!pFrame)
return FALSE;
m_pMainWnd = pFrame;
pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
// 메인프레임만 가져와서 윈도우의 형태만 띄운 것
*CWinThread를 상속받은 CUIThr은 클래스 스스로가 스레드임
UIThread.cpp안의 InitInstance()함수와 매우 유사함을 알 수 있다.
실제 UIThread.cpp의 InitInstance()함수도 윈도우를 만들어 주는 것이과
그것과 같은 역할의 코드를 UIthr.cpp내에 구현해 놓은 것이다.
9. ChildView.cpp안의 OnPaint()함수 작성
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트
CString strTmp = _T("");
strTmp.Format(_T("현재 실행되고 있는 스레드의 ID : %d"), ::GetCurrentThreadId());
dc.TextOut(10, 10, strTmp);
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
10. stdafx.h파일에 아래 메인프레임 헤더파일을 인클루드 한다(인클루드 하는 곳은 꼭 stdafx.h 파일이 아니어도 됨.
#include "MainFrm.h"
//여기까지 하면 실행되고 있는 스레드의 ID를 확인할 수 있다. 이것은 실제 윈도우가 아니라 프레임만 가져온 것!
→ 이것이 UI 이다.
■ 사용자 UI스레드를 제어하는 방법
1. stdafx.cpp에 전역변수 추가
CWinThread* g_pUIThread;
전역변수를 추가 했을 경우에는 헤더파일에 변수 선언
stdafx.h 파일에
extern CWinThread* g_pUIThread;
2. 위의 전역변수를 이용해 중복실행 막기. MainFrm.cpp안의 OnMenuCreateuithread()함수에 코드 작성
void CMainFrame::OnMenuCreateuithread()
{
if(g_pUIThread != NULL)
{
AfxMessageBox(_T("사용자 인터페이스 스레드가 이미 실행중입니다."));
return;
}
g_pUIThread = AfxBeginThread(RUNTIME_CLASS(CUIThr));
}
3. UI를 종료하였음에도 불구하고 이미 실행중이라는 메시지를 막기위해 g_pUIThread의 값을 초기화 해 주어야 한다.
UIThr.cpp의 ExitInstance() 함수에서 g_pUIThread값을 초기화 한다.
int CUIThr::ExitInstance()
{
g_pUIThread = NULL;
return CWinThread::ExitInstance();
}
스레드를 함수로 만들어서 돌릴수도 있고, 지금과 같이 클래스로 만들어서 돌릴 수도 있다.
각각 어느 경우에 사용하는것인지...
클래스로 스레드를 만들어서 사용했을 때(클래스 자체가 스레드 하나가 될 때)의 장점?
역할이 다른 여러개의 함수가 하나의 데이터를 공유하기 위한 충돌을 막을 수 있다.
스레드가 사용할 데이터를 하나의 클래스 안에 넣어서 스레드를 위해서만 공유할 수 있다.(임계영역에서의 경쟁이 없어짐)
but 단점(객체를 만들었을 때의 단점)?
스레드의 정지시점을 개별적으로 결정 할 수 없다.
하지만 이것은 스레드를 동시에 실행시키고 내릴 수 있다는 의미에서는 장점이 될 수도 있다.
1. 리소스뷰-MENU-IDR_MAINFRAME에서 위와 같은 방법으로 3개의 메뉴 추가
Resume UI Thread, Suspend UI Thread, Exit UI Thread
ID편집하고 이벤트 처리기 추가
2. MainFrm.cpp에 생성된 세 개의 함수에 각각 스레드를 재실행 시키는 코드 작성
void CMainFrame::OnMenuSuspend()
{
if (g_pUIThread != NULL)
g_pUIThread->SuspendThread();
}
void CMainFrame::OnMenuResume()
{
if (g_pUIThread != NULL)
g_pUIThread->ResumeThread();
}
void CMainFrame::OnMenuExit()
{
if (g_pUIThread != NULL)
g_pUIThread->PostThreadMessage(WM_QUIT, NULL, NULL);
}
이것을 활용하여 사용자 UI가 여러개인 프로그램을 만들 수 있다.
'PROGRAMMING > MFC(C++)' 카테고리의 다른 글
[0418수업] ThreadCrash(Critical Section, 뮤텍스) (0) | 2011.04.18 |
---|---|
[본문스크랩] |소켓 프로그래밍| 멀티 스레드(스레드 동기화) ③ (0) | 2011.04.15 |
[0415수업] Thread (0) | 2011.04.15 |
[0414수업] WorkerThread (0) | 2011.04.14 |
[0414수업] CallConvention(__cdecl, __stdcall, __fastcall) (0) | 2011.04.14 |