티스토리 뷰

출처 : codeproject.com

C, Win32, MFC에서 멀티 쓰레드 기능을 제공하는 API들에 대해 소개합니다

 

Simple Multithreaded Application in pure C, Win32 and MFC
By R.selvam 

This article explains how to create simple multithreaded applications in C Run Time Library, Microsoft Foundation classes and Win32 API functions. 

 

출처 http://www.codeproject.com/threads/crtmultithreading.asp

 


 

Introduction

시작하며

 

A thread is a path of execution. A process requires at least one thread. But, it may contain more then one thread. If the process is closed, all the threads in that process are killed automatically. When we create a thread in an application that is actually a secondary thread. In C or C++ the program entry point is main or wmain (Unicode version). In windows application the program starts in WinMain or wWinMain. When the program starts, the operating system creates the first thread. Because, Windows is a multitasking operating system.

 

하나의 쓰레드는 실행 과정의 하나의 경로이다하나의 프로세스는 적어도 하나의 쓰레드를 필요로 한다물론   이상의 쓰레드를 포함하고 있을수도 있다프로세스가 종료되면 프로세스 내의 모든 쓰레드들은 자동적으로 죽는다우리가 애플리케이션에서 하나의 쓰레드를 생성했을  쓰레드는 사실상 두번째의 쓰레드가 된다. C/C++에서 프로그램 진입 점은 main 또는 wmain(유니코드 버전)이다윈도우에서 애플리케이션 프로그램은 WinMain 또는 wWinMain에서 시작된다프로그램이 시작될 운영체제는 첫번째 쓰레드를 생성한다윈도우는 멀티태스킹 운영체제이기때문이다.

 

Thread function

쓰레드 함수

 

Thread function is like an ordinary function with long void pointer parameter. We can pass any data through void pointer data type.

 

쓰레드 함수는 보통 파일과 비슷하며 void 포인터 파라미터를 가진다우리는 void 파라미터 데이터 타입을 통해 어떠한 데이터라도 넘겨줄  있다.

 

A simple thread function looks like

 

간단한 쓰레드 함수는 다음과 같다.

 

ThreadFunction(LPVOID param)

{

    // do somthig

 

    ......

    .......

 

    //return value;

 

}

 

Thread Priorities

쓰레드 우선권

 

The thread priority controls the thread process priority. The thread priorities are following.

 

쓰레드 우선권은 쓰레드 프로세스 우선권을 통제한다쓰레드 우선권에는 다음과 같은 것들이 있다.

 

  • Highest THREAD_PRIORITY_HIGHEST
  • Above Normal THREAD_PRIORITY_ABOVE_NORMAL
  • Normal THREAD_PRIORITY_NORMAL
  • Below Normal THREAD_PRIORITY_BELOW_NORMAL
  • Idle THREAD_PRIORITY_IDLE

 

We set thread priority with the CreateThread function. We get or set thread priorities in GetThreadPriority and SetThreadPriorityWin32API functions or CWinThread’s functions which we call freely in the code. The priority functions return a BOOL value.

 

CreateThread 함수 호출시에  쓰레드 우선권을 정해준다. GetThreadPreadPriority SetThreadPriority Win32 API 함수들이나CWinThread 함수에서 우선권을 알아내거나 정해줄  있다. CWinThread 함수들은 코드 내에서 자유롭게 호출할  있다 우선권 관련 함수들은 BOOL 값을 리턴한다.

 

C Run Time Library Multithreading

런타임 라이브러리 멀티 쓰레딩

_beginthread

_beginthreadex

_endthread

_endthreadex

 

All the above c run time library functions are in the process.h header file. Make sure the Microsoft Visual Studio project setting is as multithreaded DLL. The _beginthread and _beginthreadex functions are used to create threads in C run time library. But, these functions have some differences. The _beginthreadex has some add ional parameters like security and thread address. When we create thread using _beginthread we end the thread use _endthread. The _endthread closes thread handle automatically. But, if we use _endthreadex we close the nthread handle using CloseHandle Win32 API function. The C Run Time Library contains the Thread Local Storage (TLS) internally. We can use thread local storage using API or Compiler specific code. The TlsAllocTlsFreeTlsGetValue and TlsSetValue are used to store thread specific data. Microsoft recommend that If you use_beginthread functions for C run Time Library you can not use Win32 API like ExitThread or CreateThread. Because, if use that method it might result in deadlocks. _beginthread uses multiple arguments in the thread creation. Our example program is a simple console based application. The user enters number of threads to create and then we execute each thread.

 

위에 있는 C 런타임 라이브러리 함수들은 모두 process.h 헤더 파일에 있다마이크로소프트 비주얼 스튜디오에서 프로젝트 세팅을 multithreaded DLL 해주어야 한다. _beginthread _beginthreadex 함수는 모두 C 런타임 라이브러리에서 쓰레드를 생성하는데 사용된다하지만 약간의 차이점이 있다. _beginthreadex 보안성과 쓰레드 주소와 같은  개의 추가 파라미터를 가진다. _beginthread 사용하여 쓰레드를 생성할 때는_endthread 사용하여 쓰레드를 종료해야 한다. _endthread 쓰레드 핸들을 자동으로 닫아준다.  하지만 _endthreadex 사용하게 되면CloseHandle Win32 API 함수을 사용하여 nthread 핸들을 따로 닫아주어야 한다. C 런타임 라이브러리는 쓰레드 로컬 영역(TLS) 내부에 포함하고 있다. API 컴파일러가 지원하는 코드를 사용함으로서 쓰레드 로컬 영역을 사용할  있다. TlsAlloc, TlsFree, TlsGetValue, TlsSetValue쓰레드 전용의 데이터를 저장하는데 사용된다마이크로소프트의 권장사항에 따르면 여러분이 C 런타임 라이브러리를 사용할 경우 ExitThreadCreateThread 같은 Win32 API 사용할  없다고 한다이유는 그런 식으로 사용할 경우 데드락에 걸릴 가능성이 있기 때문이다. _beginthread 쓰레드 생성시 여러 개의 인자를 사용한다우리의 예제 프로그램은 간단한 콘솔 기반의 애플리케이션이다사용자가 생성할 쓰레드를 입력하면 각각의 쓰레드를 실행한다.

 

// Secound Thread function

void ThreadProc(void *param);

 

// First thread

int main()

{

 

    int n;

    int i;

    int val = 0;

    HANDLE handle;

 

    printf("\t Thread Demo\n");

 

    printf("Enter the number of threads : ");

    scanf("%d",&n);

 

 

    for(i=1;i<=n;i++)

    {

        val = i;

        handle = (HANDLE) _beginthread( ThreadProc,0,&val); // create thread

        WaitForSingleObject(handle,INFINITE);

 

 

    }

 

 

    return 0;

}

 

 

void ThreadProc(void *param)

{

 

    int h=*((int*)param);

    printf("%d Thread is Running!\n",h);

    _endthread();

 

}

 

 

The thread waits for completion of another thread using WaitForSingleObject Win32 API function.

 

쓰레드는 WaitForSingleObject Win32 API 함수를 사용하여 다른 쓰레드가 완료될 때까지 대기한다.

 

MFC Multithreaded

MFC 멀티쓰레드

 

The CWinThread is the base class for all thread operations. MFC supports two types of threads. These are User Interface Thread and Worker thread. The user interface thread is based on windows message. The worker thread runs in the background process. (Examples, search a file in the find window or communicate with web browser in the web server) . The CWinThread supports both worker thread and User interface Threads. But, we will discuss only worker threads.

 

CWinThread 모든 쓰레드 작업에 사용되는 기본 클래스이다. MFC 두가지 형태의 쓰레드를 제공한다유저 인터페이스 쓰레드와 작업자 쓰레드이다유저 인터페이스 쓰레드는 윈도우 메시지에 기반한다작업자 쓰레드는 백그라운드 프로세스에서 실행된다. (예를 들면탐색창에서 파일을 찾거나 웹서버에서 웹브라우저와 통신한다.) CWinThread 작업자 쓰레드와 유저 인터페이스 쓰레드 모두를 지원한다하지만 우리는 작업자 쓸레드에 대해서만 생각할 것이다.

 

The MFC class hierarchy

MFC 클래스 계층도

 

CObject

    CCmdTarget

        CWinThread

            CWinApp

 

In the above class hierarchy the CWinApp application class is derived from CWinThread. So, if we create a application the thread is also created. If we create a thread, that is a secondary thread. The mother class CObject has some features like, Serialization support, Run time Class information and Debugging support. The derived class CWinThread also has the same features. The most common useful data members and member functions are the following.

 

위의 클래스 계층도에서 CWinApp 애플리케이션 클래스는 CWinThread 상속받았다때문에 우리가 애플리케이션을 실행하면 해당 쓰레드도 생성되는 것이다우리가 쓰레드를 하나 생성하면두번째 쓰레드가 된다엄마 클래스 CObject 다음과 같은 몇가지 기능을 가지고 있다. Serialization지원실시간 클래스 정보디버깅 지원파생 클래스인 CWinThread 같은 기능을 가진다대부분의 일반적인 유용한 데이터 멤버와 멤버 함수들은다음과 같다.

 

Data members

  • m_hThread The current thread handle
  • m_bAutoDelete Whether the thread has set to auto delete or not
  • m_nThreadID The current thread ID

Data Functions:

  • CreateThread Start the exec execution of thread
  • SuspendThread Increment thread suspend count. When the resume thread occur only the thread resume.
  • ResumeThread Resume the thread. Decrements the thread count stack
  • SetThreadPriority Set thread priority ( LOW, BELOW LOW or HIGH)
  • GetThreadPriority Get the thread Priority

 

Not all the member functions in MFC as class members. We can access some functions globally also. These functions begin with Afx. The AfxBeginThreadAfxEndThread are most widely useful functions in MFC thread. We create thread using AfxBeginThreadfunction. AfxBeginThread Syntax:

MFC 모든 멤버 함수들이 클래스 멤버는 아니다 개의 함수들은 전역적으로 접근될 수도 있다이러한 함수들은 Afx 시작한다. AfxBeginThread, AfxEndThread MFC 쓰레드에서 가장 널리 사용되는 함수들이다우리는 AfxBeginThread 함수를 사용하여 쓰레드를 생성한다. AfxBeginThread 문법은 다음과 같다.

 

CWinThread* AfxBeginThread( AFX_THREADPROC ThreadProc, LPVOID Param,

      int nPriority = THREAD_PRIORITY_NORMAL,UINT nStackSize = 0,

      DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

 

The ThreadProc is first Parameter in AfxBeginThread function. We use name of thread function in this parameter. We pass the void pointer arguments in this function. The return type in the function is UINT. The other arguments in AfxBeginThread are optional. The default thread priority is THREAD_PRIORITY_NORMAL. We can change this any time using CwinThreadSetThreadPriority function. We also get the thread priority.

 

ThreadProc AfxBeginThread 함수의 첫번째 파라미터이다 파라미터에 쓰레드 함수의 이름을 사용한다 함수에서 void 포인터 인수를 넘겨준다 함수의 리턴 타입은 UINT이다. AfxBeginThread 다른 인자는 선택적이다기본 쓰레드 우선권은 THREAD_PRIORITY_NORMAL이다. CwinThread::SetThreadPriority 함수를 사용하여 언제든지 바꿀  있다쓰레드 우선권을 알아낼 수도 있다.

 

The Thread terminates using AfxEndThread. The AfxEndThread has a Exit code argument list.

 

쓰레드는 AfxEndThread 종료된다. AfxEndThread 인수 리스트에 종료 코드를 가지고 있다.

 

CwinThread *pThread = AfxBeginThread( ThreadFunction, &data);

 

 

UINT ThreadFunction(LPVOID param)

{

    DWORD result =0 ;

 

    // do somthig

 

    AfxEndThread(exitCode);

    return result;

 

}

 

Win32 Multithread

Win32 멀티 쓰레드

 

Win32 Thread created by CreateThread function. The syntax in CreateThread is following

Win32 쓰레드는 CreateThread 함수로 생성된다문법은 다음과 같다.

HANDLE CreateThread(  LPSECURITY_ATTRIBUTES lpThreadAttributes,

            DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,

            LPVOID lpParameter,  DWORD dwCreationFlags, LPDWORD lpThreadId);

 

 

We terminate thread using the following methods.

1.       use TerminateThread function

2.       use ExitThread function

3.       use return

 

다음 메소드를 사용하여 쓰레드를 종료할  있다.

1.       TerminateThread 함수를 사용

2.       ExitThread 함수를 사용

3.       return  사용

 

But, Advanced Windows by Jeffery Ritcher recommends us to use the return method. TerminateThread or ExitThread function does not clear the Thread Stack properly. The GetThreadTimes is used to find the thread’s run time. The GetCurrentThreadID is to get current thread ID. The Sleep function is to sleep a particular thread for so many milliseconds. Example Sleep (1000) will sleep the thread for 1000 milliseconds. The SwithToThread is to switch to other threads. The SuspendThread is to wait until a call of resume Thread. The WaitForSingleObject is to wait when a particular thread completes its work. The WaitForMultipleObject is used for multiple events. These functions wait for following situations - Change notification, Console input, Event, Job, Mutex ,Process, Semaphore, Thread and Waitable timer.

 

하지만 Jeffery Ritcher Advaced Windows에서는 return 방식을 사용할 것을 권장한다. TerminateThread ExitThread 함수는 쓰레드 스택을 적절히 비우지 않는다. GetThreadTimes 쓰레드의 실행 시간을 알아내는데 쓰인다. GetCurrentThreadID 현재 쓰레드 ID 얻어내기 위해 사용된다. Sleep 함수는 특정 쓰레드를 정해진 millisecond(1/1000동안 재운다예를 들어 Sleep(1000) 쓰레드를 1000 millisecond 동안 재울 것이다. WaitForSingleObject 특정 쓰레드가 작업을 완료할 때까지 기다린다. WaitForMultipleObject 여러 이벤트에 대해 사용된다. 함수들은 다음의 상황에서는 대기하게 된다. – 통보 변경콘솔 입력이벤트작업뮤텍스프로세스세마포어쓰레드 그리고 대기 타이머.

 

Benefits of Threads

쓰레드의 유용성

 

The multithreaded application uses CPU 100% effectively. When we create a process, it will take more memory space. The multithreaded application shares the same process memory space. Every thread contains stack. So, the thread takes up less memory usage compared to a Process. The process may or may not contain more threads. If you run two or more threads in a process, all the threads share the process address space.

 

멀티 쓰레드가 구현된 애플리케이션은 CPU 100퍼센트 효과적으로 사용한다프로세스를 생성하면  많은 메모리 공간을 잡아먹을 것이다멀티쓰레드 애플리케이션은 같은 프로세스 메모리 영역을 공유한다모든 쓰레드는 스택을 가진다때문에 쓰레드는 프로세스에 비해  적은 메모리 사용량을 차지한다프로세스는  많은 쓰레드를 가질 수도 그렇지 않을 수도 있다여러분이 하나의 프로세스에서 두개 이상의 쓰레드를 실행하면  모든 쓰레드가 프로세스 주소 영역을 공유한다.

 

References

 About R.selvam

 

Hi

I am selvam, working as a programmer. I am interesting in C/C++, Managed C++, MFC, COM and Win32 API Programming.

If you have any problem for download code, please visit http://www15.brinkster.com/selvamselvam/

Click here to view R.selvam's online profile.

저작자 표시
신고
댓글
댓글쓰기 폼