티스토리 뷰

프로그래밍/MFC

MFC 스레드

에어버스 2016. 7. 10. 21:43

MFC 스레드

윈도우 OS에서 제공하는 스레드는 한 종류지만, MFC는 두 종류다.

1. 작업자 스레드 (Worket Thread) : 메시지 루프를 가지고 있지 않다.
         사용자 입력을 필요로 하지 않는 작업을 백그라운드로 수행할때 사용한다.

2. 사용자 인터페이스 스레드 (UI스레드, User Interface Thread) : 메시지 루프를 가지고 있다.
         메시지 루프가 있으므로 사용자 입력을 받아서 처리할 때 사용한다.

1-1 작업자 스레드 생성 함수

CWinThread* AfxBeginThread(
   AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL,
   UINT nStatusSize = 0, DWORD dwCreateFlags = 0, LPSECUTIRY_ATTRIBUTES lpSecurityAttrs = NULL);

- pfnThreadProc
스레드 실행 시작점을 나타내는 함수를 가리키는 포인터
이 함수를 제어함수(Controlling Function)이라 부르며 UINT 함수명(LPVOID pParam); 형태를 가져야 한다.
제어함수는 작업자 스레드가 시작하면 실행되며, 이 함수가 실행을 마치고 종료하면 작업자 스레드도 종료한다는 특징이 있다. 또 이 함수는 전역함수로 선언 하거나 멤버함수 일 경우는 정적 함수로 선언해야만 한다.

- pParam
제어 함수 실행 시 전달할 32비트 값
오직 32비트 값만 인자로 사용하지만, 구조체 변수 또는 동적 할당 메모리 주소 등을 인자로 사용하면 어떤 형태의 데이터도 받을 수 있다.

- nPriority
스레드 우선순위 레벨 값
0 이면 이 스레드를 생성한 부모 스레드와 같은 우선 순위를 가진다.

- nStatusSize
스레드 스택 크기를 바이트 단위로 지정
0 이면 스레드를 생성한 부모 스레드와 같은 크기의 스택을 가진다.

- dwCreateFlags
스레드 생성을 제어하는 부가적인 값
0 : 곧바로 스레드 실행
CRERATE_SUSPENDED : 스레드가 생성되지만 실행되지는 않는다. CWinThread::ResumeThread() 를 호출하면 정지된 스레드를 재실행한다.

- lpSecurityAttrs
보안 설명자(Security Descriptor)와 핸들 상속(Handle Inheritance)에 관련된 정보를 전달하는 역활을 한다.
NULL 이면 이 스레드를 생성한 부모 스레드와 같은 값이 적용된다.

AfxBeginThread()는 CWinThread 타입 스레드 객체를 동적으로 생성하고 (스레드를 만든 후) 이 객체의 주소값을 리턴한다. 이 주소값을 저장해두고 CWinThread 클래스의 멤버 함수를 호출하면 스레드를 제어할 수 있다.

int CWinThread::GetThreadPriority() - 스레드 우선 순위 레벨 값을 얻는다.
BOOL CWinThread::SetThreadPriority(int nPriority) - 스레드 우선 레벨값을 변경
DWORD CWinThread::SuspendTHread() - 스레드 실행을 일시 정지
DWORD CWinTHread::ResumeThread() - 정지된 스레드를 재실행

작업자 스레드 종료

방법1. 스레드 제어 함수가 리턴과 더불어 리턴값이 0이면 일반적으로 정상적인 종료를 뜻한다.
스레드 제어 함수 리턴과 더불어 스레드 스택이 파괴되며 스레드 객체(CWinThread타입)도 메모리에서 제거된다.
스레드를 파괴하지 않는 방법>

1
2
3
CWinThread* pThread = AfxBeginThread(MyFunc, NULL, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->ResumeThread();
cs

방법2.스레드 제어 함수 내에서 AfxEndThread() 를 호출한다.
호출 방법에 따라 종료 시 동작이 달라진다.
void AFXAPI AfxEndThread(UINT nExitCode, BOOL bDelete = TRUE);
-nExitCode : 스레드 종료 코드
- bDelete : 스레드 객체를 메모리에서 제거 할 것인지 나타낸다.기본값인 TRUE면 방법1과 같고 FALSE면 스레드가 종료하더라도 스레드 객체는 계속 메모리에 남아있게 되므로 스레드 객체를 재사용할 수 있다.

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
BEGIN_MESSAGE_MAP(CMFCApplication6View, CView)
    ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()
 
UINT CalcIt(LPVOID arg)
{
    int val = (int)arg;
    int result = 0;
    for (int i = 0; i < val; i++)
    {
        result += i;
        Sleep(10);
    }
    CString str;
    str.Format(L"계산 결과 = %d", result);
    AfxMessageBox(str);
    return 0;
}
 
void CMFCApplication6View::OnLButtonDblClk(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
    int val = 600;
    //CalcIt((LPVOID)val);
    AfxBeginThread(CalcIt, (LPVOID)val);
 
    CView::OnLButtonDblClk(nFlags, point);
}
cs

24행을 주석 해제하고 25행을 주석처리해서 실행하면 아래 그림과 같이 계산 결과가 나올때까지 윈도우 이동이나 메뉴 선택을 할 수 없게된다.

25행 같이 계산 루틴(CalcIt())을 스레드로 하면 계산 하는 동안 윈도우 이동과 메뉴 선택이 가능해진다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
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
29 30