Thread
1. Thread
프로세스 내에서 실행되는 각각의 작업 또는 실행 경로.
프로세스 내에서 실행되는 세부 작업단위(여러 개의 Thread가 모여서 하나의 프로세스를 이룸)
수행 중 또 다른 수행을 할 수 있습니다.
프로세스는 실행 파일이 실행 될 때 만들어지며 운영체제는 내부적으로 이러한 프로세스를 여러 논리적 코드로 분할하여 관리하게 됩니다.
이 단위를 Thread라고 합니다.
프로세스는 반드시 하나 이상의 Thread가 생성되어 실행됩니다.
프로세스는 동시에 움직이지는 않고 서로 병행적으로 움직입니다.
멀티 태스킹은 여러 개의 프로세스를 번갈아 가면서 수행하는 것이고 멀티 Thread는 하나의 프로그램을 여러 개의 기능으로 나누어 이를 동시에 실행시키는 것을 의미 합니다.
Thread 종류
1) 사용자 인터페이스 스레드: 메시지를 받을 수 있는 스레드로 프로그램의 실행과는 독립적으로 메시지를 받아서 수행하는 스레드
탐색기가 대표적인 예
2) 작업자 스레드: 백그라운드 작업을 수행하는 스레드로 메시지를 받을 수 없는 스레드
Thread를 사용한 경우와 그렇지 않은 경우의 차이
1. MFC 프로젝트 작성(SDI 옵션 프로젝트명 Thread)
2. 전역 함수로 작성(APP 클래스의 빈 부분에 작성하면 됩니다.)
UINT MyThreadFunc(LPVOID lparam)
{
RECT rect;
CDC *pDC;
CString m_str;
CThreadView *pView;
pView=(CThreadView*) lparam;
pView->GetClientRect(&rect);
pDC=pView->GetDC();
for(int i =0; i<40; i++)
{
pDC->Rectangle(i*20,10, i*20+20,30);
Sleep(500);
}
pView->ReleaseDC(pDC);
return 0;
}
3. View 클래스의 마우스 왼쪽 버튼 클릭 메시지 작성
MyThreadFunc((LPVOID)this);
4. 위의 메시지 수정
AfxBeginThread(MyThreadFunc,(LPVOID)this);
2. 작업자(Worker) Thread
AfxBeginThread함수를 호출하기만 하면 됩니다.
CWinThread* AfxBeginThread(Thread로 동작할 함수, 부가정보, 우선순위, 스택 사이즈, 실행여부, 보안을 위한 설정);
스레드로 동작할 함수는 전역으로 선언하거나 static 함수로 선언되어야 합니다.
부가정보는 일반적으로 LPVOID pParam으로 임의의 4바이트 변수를 넘겨 줄 수 있습니다.
만일 4바이트 이상의 부가정보를 넘겨주고자 하는 경우는 구조체를 생성해서 넘겨주면 됩니다.
우선 순위는 실행의 우선 순위입니다.
스택 사이즈는 0을 주면 1MB까지 스택을 사용할 수 있게 되고 다른 사이즈를 지정하면 그 크기만큼 스택의 사이즈를 사용할 수 있습니다.
실행여부는 0을 지정하면 바로 실행되고 CREATE_SUSPENDED를 지정하면 Thread가 생성만 되고 ResumeThread를 만날 때까지 실행을 멈추고 있게 됩니다.
이 함수는 정상적으로 수행되면 Thread의 주소를 리턴합니다.
만일 Thread를 중지하거나 계속 수행, 종료 등을 하고자 한다면 Thread의 주소를 받는 변수를 만들어서 사용해야 합니다.
전역 함수 GetCurrentThreadId()를 이용하면 현재 수행 중인 스레드의 ID를 알 수 있습니다.
Thread에 사용하는 함수
ð GetThreadPriority(): 우선순위 값 리턴
ð SetThreadPriority(int nPriority): 우선순위 변경
THREAD_PRIORITY_TIME_CRITICAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_IDLE
ð SuspendThread(): Thread 중지
ð ResumeThread(): Thread 재 실행
멤버 변수 중에서 m_hThread가 Thread의 핸들을 리턴합니다.
사용방법
CWinThread * Thread 연결할 변수 = AfxBeginThread();
변수명->함수 호출
Thread의 종료
- 강제 종료
TerminateThread(Thread핸들, 0);
- 스레드가 수행할 함수에게 넘겨주는 매개 변수에 flag 변수를 하나 설정하여 그 값이 TRUE일 때만 수행하게 하고 주 프로세스에서 그 값을 FALSE로 변경하게 해서 종료 시킬 수 있습니다.
WaitForSingleObject()사용
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
hHandle: 스레드 핸들
dwMilliseconds:1/1000초 단위 시간
리턴값
WAIT_OBJECT_0: 스레드의 수행이 종료
WAIT_TIMEOUT: 현재 스레드가 수행 중 임
위의 함수를 이용하면 스레드가 종료된 후 다른 작업을 수행할 수 있으며 스레드의 현재 상태도 조사가 가능합니다.
여러 개의 스레드의 상태 조사
WaitForMultipleObjects(스레드 핸들 개수, 핸들 배열의 주소, TRUE이면 모든 스레드의 상태이고 FALSE이면 아무 스레드나 한 개의 상태,시간, 사용할 메시지에 따른 옵션)
리턴 값
WAIT_OBJECT_0 + nCount: 몇 개가 신호를 받았는지 여부
WAIT_TIMEOUT: 수행 중인 경우
Thread의 현재 상태 알아보기
CString temp;
DWORD dwExitcode=0;
GetExitCodeThread(Thread핸들->m_hThread, &dwExitcode);
temp.Format(TEXT("%d"), dwExitcode);
AfxMessageBox( temp );
Thread 예제(하나의 매개변수만 넘겨주는 경우)
Thread 예제(2개 이상의 매개변수를 넘겨주는 경우)
View 클래스의 마우스 중간 버튼 클릭 메시지에 작성
3. 멀티 Thread
2개 이상의 스레드가 동시에 수행되는 경우를 멀티 스레드라고 합니다.
Thread의 우선 순위 변경 예제
멀티 Thread의 문제점
1. SDI 옵션으로 프로젝트 생성(MultiThread)
2. 전역 변수를 선언하고 2개의 Thread 함수 작성
int X;
UINT ThreadFunc1(LPVOID Param)
{
CDC *pDC;
CMultiThreadView *pView;
pView=(CMultiThreadView*)Param;
pDC=pView->GetDC();
for (int i=0;i<100;i++)
{
X=100;
Sleep(1);
pDC->TextOut(X,100,TEXT("Hello"),5);
}
return 0;
}
UINT ThreadFunc2(LPVOID Param)
{
CDC *pDC;
CMultiThreadView *pView;
pView=(CMultiThreadView*)Param;
pDC=pView->GetDC();
for (int i=0;i<100;i++)
{
X=200;
Sleep(1);
pDC->TextOut(X,200,TEXT("World"),5);
}
return 0;
}
3. View클래스의 LButtonDown에 작성
AfxBeginThread(ThreadFunc1,(LPVOID)this);
AfxBeginThread(ThreadFunc2,(LPVOID)this);
멀티Thread를 제어하는 방법
임계영역(CriticalSection), 상호배제(Mutex), 이벤트 처리(Event), 세마포어(Semaphore) 등이 있습니다.
afxmt.h 파일에 모두 존재하므로 위의 기능을 사용하고자 하는 경우 이를 include 해 주어야 합니다.
1)임계영역(CriticalSection),
공유자원을 사용하는 코드 영역
하나의 Thread가 임계 영역에 접근할 경우 Thread는 다른 Thread가 이 영역에 접근할 수 없도록 이 영역에 Lock을 걸어 주며 임계 영역의 수행이 끝나게 되면 Lock을 해제해서 다른 Thread가 임계영역에 접근할 수 있도록 제어하게 됩니다.
멤버 함수
Lock()
Unlock()
1. stdafx.h 파일에 헤더파일 추가
#include <afxmt.h>
2. 다음의 변수를 추가
전역 변수로 추가
CCriticalSection g_cs;
3. 공통되는 자원을 사용하는 코드 영역을 다음 2개의 함수로 묶음
g_cs.Lock();
g_cs.Unlock();
2) CMutex
CMutex 클래스를 사용해도 동일한 효과를 얻을 수 있습니다.
일반적으로 CMutex는 여러 개의 프로그램(DLL)이 하나의 자원을 공유하는 경우에 사용합니다.
3) CEvent 이용
CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);
1 번째 값은 처음 초기화 될 때의 신호 여부를 의미하는데 FALSE이면 Event가 설정되지 않은 상태로 생성됩니다.
2번째 값은 한번 설정된 값을 계속 유지할 것인지 여부를 지정하는 옵션으로 기본값은 FALSE인데 이렇게 되면 WaitForSingleObject()가 계속해서 WAIT_OBJECT_0을 반환합니다.
TRUE이면 자동으로 모든 Lock()을 해제합니다.
lpszName은 이름입니다.
마지막은 보안속성입니다.
공통 코드영역에서 이벤트 오브젝트.PulseEvent(); 를 설정해서 이 코드를 만나면 이벤트를 발생시킵니다.
이벤트 오브젝트.Lock();을 이용해서 다른 코드 영역을 묶어 줍니다.
이벤트의 이름을 적절히 활용하면 다른 프로세스의 제어가 가능합니다.
4) CSemaphore
CSemaphore(LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttributes = NULL);
lInitialCount: 처음에 수행할 스레드 개수
lMaxCount: 최대 스레드 개수
pstrName: 세마포어 객체의 이름
lpsaAttributes: 보안 속성으로 NULL이면 생성자 스레드의 권한을 가짐
스레드가 2개 이상이 동시에 수행되어야 할 때 사용하는 클래스입니다.
초기값과 최대값은 일반적으로 동일 한 값을 주면 됩니다.
Lock()와 Unlock()멤버 함수를 이용해서 공통 코드 영역을 묶어 주면 됩니다.
5) CMultiLock
여러 개의 이벤트가 발생해야만 수행되는 상호배제를 만들 때 사용
CEvent g_Ev[개수];
CMultiLock mLock(g_Ev, 개수);
m_Lock.Lock()으로 묶으면 개수 만큼의 이벤트가 발생해야 만 해제 됨
m_Lock.Lock(INFINITE, 개수)로 묶으면 한 개라도 이벤트가 발생하면 해제 됨
예제) CSemaphore 사용
예제)CEvent를 이용한 여러 개의 프로그램 종료(다른 프로그램에 종료)
3. UI Thread
메시지 루프를 가지고 있어서 사용자의 입력이나 메시지 형태로 전달되는 이벤트를 처리할 수 있는 Thread
자체적으로 메시지 루프를 갖기 때문에 메시지를 받을 수 있어서 PostThreadMessage(메시지 종류, WPARAM, LPARAM)를 이용해서 메시지를 전달받아서 수행 할 수도 있습니다.
InitInstance 함수에서 윈도우를 생성해서 별도의 윈도우를 제어할 수 도 있습니다.
1) 생성
CWinThread 클래스로부터 상속받는 클래스 생성
2) 원하는 함수 재정의(Run 메소드 재정의)
Run 메소드가 스레드가 수행 할 내용을 정의
3) UI Thread의 실행
CWinThread * AfxBeginThread(
CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);
스레드의 주소를 리턴함
pThreadClass: 스레드로 수행할 클래스 이름
nPriority: 스레드 우선 순위
nStackSize: 스택 크기
dwCreateFlags: 초기 실행 여부
lpSecurityAttrs: 보안을 위한 옵션
'C & C++ > C & C++' 카테고리의 다른 글
메시지 훅(Message Hook) (0) | 2011.04.25 |
---|---|
[MFC] 프로세스 간의 통신 (0) | 2011.04.25 |
[MFC] Sheel 프로그래밍 (0) | 2011.04.25 |
[MFC] DLL( Dynamic Linking Library) (0) | 2011.04.25 |
[MFC] 파일 입출력 (0) | 2011.04.25 |
댓글