다중 스레딩: MFC에서 작업자 스레드 만들기
작업자 스레드는 일반적으로 사용자가 애플리케이션을 계속 사용할 때까지 기다릴 필요가 없는 백그라운드 작업을 처리하는 데 사용됩니다. 재계산 및 배경 인쇄와 같은 작업은 작업자 스레드의 좋은 예입니다. 이 항목에서는 작업자 스레드를 만드는 데 필요한 단계를 자세히 설명합니다. 다룰 주제는 다음과 같습니다.
작업자 스레드를 만드는 작업은 비교적 간단한 작업입니다. 스레드를 실행하려면 제어 함수를 구현하고 스레드를 시작하는 두 단계만 필요합니다. CWinThread에서 클래스를 파생시킬 필요는 없습니다. 특수 버전 CWinThread
이 필요한 경우 클래스를 파생시킬 수 있지만 대부분의 간단한 작업자 스레드에는 필요하지 않습니다. 수정 없이 사용할 CWinThread
수 있습니다.
스레드 시작
오버로드된 버전에는 작업자 스레드만 만들 수 있는 버전 AfxBeginThread
과 사용자 인터페이스 스레드와 작업자 스레드를 모두 만들 수 있는 버전이 있습니다. 첫 번째 오버로드를 사용하여 작업자 스레드 실행을 시작하려면 AfxBeginThread를 호출하여 다음 정보를 제공합니다.
제어 함수의 주소입니다.
제어 함수에 전달할 매개 변수입니다.
(선택 사항) 스레드의 원하는 우선 순위입니다. 기본값은 일반 우선 순위입니다. 사용 가능한 우선 순위 수준에 대한 자세한 내용은 Windows SDK의 SetThreadPriority를 참조하세요.
(선택 사항) 스레드에 대해 원하는 스택 크기입니다. 기본값은 만드는 스레드와 동일한 크기 스택입니다.
(선택 사항) 스레드를 일시 중단된 상태로 만들려면 CREATE_SUSPENDED. 기본값은 0이거나 스레드를 정상적으로 시작합니다.
(선택 사항) 원하는 보안 특성입니다. 기본값은 부모 스레드와 동일한 액세스입니다. 이 보안 정보의 형식에 대한 자세한 내용은 Windows SDK의 SECURITY_ATTRIBUTES 참조하세요.
AfxBeginThread
는 개체를 CWinThread
만들고 초기화하고, 개체를 시작하고, 나중에 참조할 수 있도록 해당 주소를 반환합니다. 생성의 일부가 실패할 경우 모든 개체의 할당이 제대로 취소되었는지 확인하기 위해 프로시저 전체에서 검사가 수행됩니다.
제어 함수 구현
제어 함수는 스레드를 정의합니다. 이 함수를 입력하면 스레드가 시작되고 스레드가 종료되면 스레드가 종료됩니다. 이 함수에는 다음 프로토타입이 있어야 합니다.
UINT MyControllingFunction( LPVOID pParam );
매개 변수는 단일 값입니다. 이 매개 변수에서 함수가 받는 값은 스레드 개체를 만들 때 생성자에 전달된 값입니다. 제어 함수는 선택한 방식으로 이 값을 해석할 수 있습니다. 여러 매개 변수를 포함하는 구조체에 대한 스칼라 값 또는 포인터로 처리되거나 무시될 수 있습니다. 매개 변수가 구조를 참조하는 경우 구조를 사용하여 호출자에서 스레드로 데이터를 전달할 뿐만 아니라 스레드에서 호출자에게 데이터를 다시 전달할 수도 있습니다. 이러한 구조를 사용하여 데이터를 호출자에게 다시 전달하는 경우 스레드는 결과가 준비되면 호출자에게 알려야 합니다. 작업자 스레드에서 호출자에게 통신하는 방법에 대한 자세한 내용은 다중 스레딩: 프로그래밍 팁 참조하세요.
함수가 종료되면 종료 이유를 나타내는 UINT 값을 반환해야 합니다. 일반적으로 이 종료 코드는 다른 유형의 오류를 나타내는 다른 값으로 성공을 나타내는 0입니다. 이는 전적으로 구현에 따라 달라집니다. 일부 스레드는 개체의 사용 횟수를 기본 해당 개체의 현재 사용 수를 반환할 수 있습니다. 애플리케이션에서 이 값을 검색하는 방법을 보려면 다중 스레딩: 스레드 종료를 참조 하세요.
MFC 라이브러리로 작성된 다중 스레드 프로그램에서 수행할 수 있는 작업은 몇 가지 제한 사항이 있습니다. 이러한 제한 사항에 대한 설명과 스레드 사용에 대한 기타 팁은 다중 스레딩: 프로그래밍 팁 참조하세요.
함수 제어 예제
다음 예제에서는 제어 함수를 정의하고 프로그램의 다른 부분에서 사용하는 방법을 보여줍니다.
UINT MyThreadProc( LPVOID pParam )
{
CMyObject* pObject = (CMyObject*)pParam;
if (pObject == NULL ||
!pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
return 1; // if pObject is not valid
// do something with 'pObject'
return 0; // thread completed successfully
}
// inside a different function in the program
.
.
.
pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
.
.
.