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가 여러개인 프로그램을 만들 수 있다.


Posted by 마마필로 :