MultiThread 예제 분석
C++ 2008. 12. 30. 14:56 |/* file Main.cpp
*
* This program is an adaptation of the code Rex Jaeschke showed in
* Listing 4 of his Nov 2005 C/C++ User's Journal article entitled
* "C++/CLI Threading: Part II". I changed it from C++/CLI (managed)
* code to standard C++.
*
* One hassle is the fact that C++ must employ a free (C) function
* or a static class member function as the thread entry function.
*
* This program must be compiled with a multi-threaded C run-time
* (/MT for LIBCMT.LIB or /MTd for LIBCMTD.LIB).
*
* John Kopplin 7/2006
*/
#include <stdio.h>
#include <windows.h> // for HANDLE
#include <process.h> // for _beginthread()
static bool interlocked = false; // change this to fix the problem
const int maxCount = 100000000;
static LONG value = 0; // under Windows Server 2003 you
// could use LONGLONG here
unsigned __stdcall TMain(void* arg)
{
if ( interlocked )
{
for ( int i = 1; i <= maxCount; i++ )
{
InterlockedIncrement(&value); // under Windows Server 2003 you
// could use InterlockedIncrement64() here
}
}
else
{
for ( int i = 1; i <= maxCount; i++ )
{
++value;
}
}
return 3; // thread exit code
}
int main()
{
// In this program we create 3 threads and request that their
// entry-point-function be the TMain() function which is a
// free (C) function and hence causes no problems for
// _beginthreadex()
HANDLE hth1;
unsigned uiThread1ID;
(원형) unsigned long _beginthread( void (*lpThreadEntryPoint)(void* lpArgList), unsigned uStackSize, void* lpArgList );
lpThreadEntryPoint 는 스레드가 시작된 함수의 주소인데, 이 함수에는 CreateThread()와 같이 한 개의 32비트 인자인 lpArgList가 있으며 이 값을 _beginthread()에 전달해야 한다. 이 함수는 void 타입으로 정의되어 CreateThread()와 조금 차이가 있다. 이 함수는 종료시까지 실행되는데 값을 반환하지는 않는다. uStackSize는 CreateThread()에서와 동일한 의미를 가지는데 스레드 스택의 베이스에서 커멧될 바이트 수이며, 이 값을 0으로 하면 윈도우는 부모 스레드에서 커멧된 것과 동일한 양의 메모리를 커멧힌다.
_beginthreadex() 는 CreateThread()와 완전히 같고 SECURITY_ATTRIBUTES 포인터와 시작 플래그(0이나 CREATE_SUSPENDED), 스레드 ID를 받는 포인터를 인자로 받는다. 일시 정지된 상태에서 스레드를 시작하거나 PostThreadMessage()에 스레드 ID를 사용하려면 _beginthreadex()를 사용해야 한다. _beginthread()
로 시작한 스레드만이 종료 코드를 설정할 수 있으므로 이때에도 필요하다.
hth1 = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
TMain, // entry-point-function
NULL, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread1ID );
if ( hth1 == 0 )
printf("Failed to create thread 1\n");
DWORD dwExitCode;
스레드에서 return 문이 등장하면 윈도우는 ExitThread()를 대신 호출해서 return 문에 전달된 값을 전달해 주는데, 이 때문에 입구 함수는 DWORD의 반환값을 갖는다.
스레드를 시작하는 방법이 여러가지 있고 각각의 종료 함수도 다르므로 스레드에서는 단순히 return문을 사용하는 것이 좋다.
GetExitCodeThread( hth1, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "initial thread 1 exit code = %u\n", dwExitCode );
HANDLE hth2;
unsigned uiThread2ID;
hth2 = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
TMain, // entry-point-function
NULL, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread2ID );
if ( hth2 == 0 )
printf("Failed to create thread 2\n");
GetExitCodeThread( hth2, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "initial thread 2 exit code = %u\n", dwExitCode );
HANDLE hth3;
unsigned uiThread3ID;
hth3 = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
TMain, // entry-point-function
NULL, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread3ID );
if ( hth3 == 0 )
printf("Failed to create thread 3\n");
GetExitCodeThread( hth3, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "initial thread 3 exit code = %u\n", dwExitCode );
// If we hadn't specified CREATE_SUSPENDED in the call to _beginthreadex()
// we wouldn't now need to call ResumeThread().
ResumeThread( hth1 ); // Jaeschke's // t1->Start();
ResumeThread( hth2 ); // Jaeschke's // t2->Start();
ResumeThread( hth3 ); // Jaeschke's // t3->Start();
// In C++ the process terminates when the primary thread exits
// and when the process terminates all its threads are then terminated.
// Hence if you comment out the following waits, the non-primary
// threads will never get a chance to run.
WaitForSingleObject( hth1, INFINITE ); // Jaeschke's t1->Join()
WaitForSingleObject( hth2, INFINITE ); // Jaeschke's t2->Join()
WaitForSingleObject( hth3, INFINITE ); // Jaeschke's t3->Join()
GetExitCodeThread( hth1, &dwExitCode );
printf( "thread 1 exited with code %u\n", dwExitCode );
GetExitCodeThread( hth2, &dwExitCode );
printf( "thread 2 exited with code %u\n", dwExitCode );
GetExitCodeThread( hth3, &dwExitCode );
printf( "thread 3 exited with code %u\n", dwExitCode );
printf( "After %d operations, value = %d\n", 3 * maxCount, value );
// under Windows Server 2003 you
// could use %I64d
// The handle returned by _beginthreadex() has to be closed
// by the caller of _beginthreadex().
CloseHandle( hth1 );
CloseHandle( hth2 );
CloseHandle( hth3 );
printf("Primary thread terminating.\n");
}