1. 정적 TLS
2. 동적 TLS
3. 알고리즘 시간을 측정
4. 스레드에 메시지 루프 집어넣기
5. 스레드에서 주 스레드로 메시지 보내기
6. 공유메모리
7. 공유메모리의 DLL화
more..
// 정적 TLS의 문제점 : DLL에 만들고.. 해당 DLL을 LoadLibrary로 사용하면 TLS에 있는 변수가
// 제대로 동작하지 않는다. => 동적 TLS를 사용하자.
// 3의 배수를 차례대로 리턴하는 함수
// single Thread에서는 문제없다.
int Next3Times()
{
// 정적 TLS : static 지역 변수 혹은 전역 변수에만 사용가능..
__declspec(thread) static int n = 0;
n = n + 3;
return n;
}
DWORD WINAPI foo( void* p )
{
char* n = (char*)p;
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
return 0;
}
int main()
{
HANDLE h[2];
h[0] = CreateThread( 0, 0, foo, "A", 0, 0 );
h[1] = CreateThread( 0, 0, foo, "\tB", 0, 0 );
getch();
}
// 제대로 동작하지 않는다. => 동적 TLS를 사용하자.
// 3의 배수를 차례대로 리턴하는 함수
// single Thread에서는 문제없다.
int Next3Times()
{
// 정적 TLS : static 지역 변수 혹은 전역 변수에만 사용가능..
__declspec(thread) static int n = 0;
n = n + 3;
return n;
}
DWORD WINAPI foo( void* p )
{
char* n = (char*)p;
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
return 0;
}
int main()
{
HANDLE h[2];
h[0] = CreateThread( 0, 0, foo, "A", 0, 0 );
h[1] = CreateThread( 0, 0, foo, "\tB", 0, 0 );
getch();
}
2. 동적 TLS
more..
// 전역변수( 모든 스레드 공유 )로 TLS Index를 보관한다.
DWORD index = 0;
int Next3Times()
{
DWORD n = (DWORD)TlsGetValue( index ); // TLS에서 값을 꺼내서
n = n + 3; // 증가하고
TlsSetValue( index, (LPVOID) n ); // 다시 보관한다.
return n;
}
DWORD WINAPI foo( void* p )
{
// TLS 초기값을 설정한다.
TlsSetValue( index, 0 );
char* n = (char*)p;
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
return 0;
}
int main()
{
// 스레드를 생성하기 전에 동적으로 TLS의 빈 슬롯(4byte)을 할당한다.
index = TlsAlloc();
HANDLE h[2];
h[0] = CreateThread( 0, 0, foo, "A", 0, 0 );
h[1] = CreateThread( 0, 0, foo, "\tB", 0, 0 );
WaitForMultipleObjects( 2, h, TRUE, INFINITE );
TlsFree( index ); // TLS를 해지한다.
}
DWORD index = 0;
int Next3Times()
{
DWORD n = (DWORD)TlsGetValue( index ); // TLS에서 값을 꺼내서
n = n + 3; // 증가하고
TlsSetValue( index, (LPVOID) n ); // 다시 보관한다.
return n;
}
DWORD WINAPI foo( void* p )
{
// TLS 초기값을 설정한다.
TlsSetValue( index, 0 );
char* n = (char*)p;
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
printf( "%s : %d\n", n, Next3Times() );
return 0;
}
int main()
{
// 스레드를 생성하기 전에 동적으로 TLS의 빈 슬롯(4byte)을 할당한다.
index = TlsAlloc();
HANDLE h[2];
h[0] = CreateThread( 0, 0, foo, "A", 0, 0 );
h[1] = CreateThread( 0, 0, foo, "\tB", 0, 0 );
WaitForMultipleObjects( 2, h, TRUE, INFINITE );
TlsFree( index ); // TLS를 해지한다.
}
3. 알고리즘 시간을 측정
more..
void get_thread_time( HANDLE hThread, __int64* usertime, __int64* kerneltime )
{
// 스레드의 생성시간, 종료시간, 커널시간, user시간을 구한다.
__int64 t1, t2;
GetThreadTimes( hThread, (FILETIME*)&t1, // 생성시간
(FILETIME*)&t2, // 종료시간
(FILETIME*)kerneltime, // 커널에서 실행한 시간
(FILETIME*)usertime ); // 유저모드에서 실행한 시간
}
int factorial( int a )
{
if( a == 1 ) return 1;
return a * factorial( a-1 );
}
int main()
{
__int64 k1 = 0, k2 = 0, u1 = 0, u2 = 0;
get_thread_time( GetCurrentThread(), &u1, &k1 );
// 시간을 측정하고 싶은 알고리즘
for ( int i = 0; i < 1000; ++i )
printf( "%d\n", factorial(10) );
get_thread_time( GetCurrentThread(), &u2, &k2 );
printf( "걸린시간 : %d ms\n", ( (u2-u1) + (k2-k1))/10);
}
{
// 스레드의 생성시간, 종료시간, 커널시간, user시간을 구한다.
__int64 t1, t2;
GetThreadTimes( hThread, (FILETIME*)&t1, // 생성시간
(FILETIME*)&t2, // 종료시간
(FILETIME*)kerneltime, // 커널에서 실행한 시간
(FILETIME*)usertime ); // 유저모드에서 실행한 시간
}
int factorial( int a )
{
if( a == 1 ) return 1;
return a * factorial( a-1 );
}
int main()
{
__int64 k1 = 0, k2 = 0, u1 = 0, u2 = 0;
get_thread_time( GetCurrentThread(), &u1, &k1 );
// 시간을 측정하고 싶은 알고리즘
for ( int i = 0; i < 1000; ++i )
printf( "%d\n", factorial(10) );
get_thread_time( GetCurrentThread(), &u2, &k2 );
printf( "걸린시간 : %d ms\n", ( (u2-u1) + (k2-k1))/10);
}
4. 스레드에 메시지 루프 집어넣기
more..
#include <commctrl.h> // 공용 컨트롤 헤더
// 스레드간 메세지 통신...
DWORD WINAPI foo( void* p )
{
TCHAR szApp[] = _T("BBB");
ATOM atom;
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground= (HBRUSH)GetStockObject( WHITE_BRUSH );
wc.hCursor = LoadCursor( 0, IDC_ARROW );
wc.hIcon = LoadIcon( 0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = WndProc;
wc.lpszClassName= szApp;
wc.lpszMenuName = 0;
wc.style = 0;
atom = RegisterClass( &wc);
if ( atom == 0 )
{
MessageBox( 0, _T("Fail To RegisterClass"), _T("Error"), MB_OK);
return 0;
}
hwnd = CreateWindowEx( 0, szApp, szApp, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT,0, 0, 0,
0, 0);
ShowWindow( hwnd, SW_SHOW);
UpdateWindow( hwnd );
while ( GetMessage( &msg, 0, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage( &msg);
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hPrg;
switch( msg )
{
case WM_CREATE:
hPrg = CreateWindow( PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | WS_BORDER,
10,10,500,30, hwnd, (HMENU)1, 0,0);
SendMessage( hPrg, PBM_SETRANGE32,0,1000);
return 0;
case WM_LBUTTONDOWN:
{
HANDLE h = CreateThread( 0, 0, foo, (void*)hwnd, 0, 0);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
// 스레드간 메세지 통신...
DWORD WINAPI foo( void* p )
{
TCHAR szApp[] = _T("BBB");
ATOM atom;
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground= (HBRUSH)GetStockObject( WHITE_BRUSH );
wc.hCursor = LoadCursor( 0, IDC_ARROW );
wc.hIcon = LoadIcon( 0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = WndProc;
wc.lpszClassName= szApp;
wc.lpszMenuName = 0;
wc.style = 0;
atom = RegisterClass( &wc);
if ( atom == 0 )
{
MessageBox( 0, _T("Fail To RegisterClass"), _T("Error"), MB_OK);
return 0;
}
hwnd = CreateWindowEx( 0, szApp, szApp, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT,0, 0, 0,
0, 0);
ShowWindow( hwnd, SW_SHOW);
UpdateWindow( hwnd );
while ( GetMessage( &msg, 0, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage( &msg);
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hPrg;
switch( msg )
{
case WM_CREATE:
hPrg = CreateWindow( PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | WS_BORDER,
10,10,500,30, hwnd, (HMENU)1, 0,0);
SendMessage( hPrg, PBM_SETRANGE32,0,1000);
return 0;
case WM_LBUTTONDOWN:
{
HANDLE h = CreateThread( 0, 0, foo, (void*)hwnd, 0, 0);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
5. 스레드에서 주 스레드로 메시지 보내기
more..
// 스레드간 메세지 통신...
DWORD WINAPI foo( void* p )
{
HWND hwnd = (HWND)p;
for ( int i=0; i< 1000; ++i )
{
// 생성된 프로그레스바에 메시지를 보낸다.
SendMessage( hPrg, PBM_SETPOS, i, 0);
Sleep(10);
// 주스레드에 직접 메세지를 보내서 자신을 스스로 Update가 되게 하다.
BOOL b = PostMessage( hwnd, WM_USER+100, i, 0);
if ( b == FALSE ) break;
Sleep( 10 );
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hPrg;
switch( msg )
{
case WM_CREATE:
hPrg = CreateWindow( PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | WS_BORDER,
10,10,500,30, hwnd, (HMENU)1, 0,0);
SendMessage( hPrg, PBM_SETRANGE32,0,1000);
return 0;
case WM_RBUTTONDOWN:
{
while(1);
}
return 0;
case WM_LBUTTONDOWN:
{
HANDLE h = CreateThread( 0, 0, foo, (void*)hwnd, 0, 0);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
DWORD WINAPI foo( void* p )
{
HWND hwnd = (HWND)p;
for ( int i=0; i< 1000; ++i )
{
// 생성된 프로그레스바에 메시지를 보낸다.
SendMessage( hPrg, PBM_SETPOS, i, 0);
Sleep(10);
// 주스레드에 직접 메세지를 보내서 자신을 스스로 Update가 되게 하다.
BOOL b = PostMessage( hwnd, WM_USER+100, i, 0);
if ( b == FALSE ) break;
Sleep( 10 );
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hPrg;
switch( msg )
{
case WM_CREATE:
hPrg = CreateWindow( PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | WS_BORDER,
10,10,500,30, hwnd, (HMENU)1, 0,0);
SendMessage( hPrg, PBM_SETRANGE32,0,1000);
return 0;
case WM_RBUTTONDOWN:
{
while(1);
}
return 0;
case WM_LBUTTONDOWN:
{
HANDLE h = CreateThread( 0, 0, foo, (void*)hwnd, 0, 0);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
6. 공유메모리
more..
// 일반 전역 변수.. .data section에 놓인다. 기본적으로 COW하는 속성을 가지고 있다.
int x = 0;
// exe에 새로운 data 섹션을 만든다.
#pragma data_seg("AAA")
int y = 0; // 공유 섹션으로 만드려면 반드시 초기값이 필요하다.
#pragma data_seg()
// 특정 섹션의 속성을 지정한다. - Read, Write, Share( COW 속성이 제거된다. )
#pragma comment( linker, "/section:AAA,RWS") // Copy On Write
int main()
{
++x; ++y;
if( y >= 3 )
{
printf( "3번 이상은 실행하지 마세요\n" );
--y;
return 0;
}
printf( "x = %d, y = %d\n", x, y );
_getch();
}
int x = 0;
// exe에 새로운 data 섹션을 만든다.
#pragma data_seg("AAA")
int y = 0; // 공유 섹션으로 만드려면 반드시 초기값이 필요하다.
#pragma data_seg()
// 특정 섹션의 속성을 지정한다. - Read, Write, Share( COW 속성이 제거된다. )
#pragma comment( linker, "/section:AAA,RWS") // Copy On Write
int main()
{
++x; ++y;
if( y >= 3 )
{
printf( "3번 이상은 실행하지 마세요\n" );
--y;
return 0;
}
printf( "x = %d, y = %d\n", x, y );
_getch();
}
7. 공유메모리의 DLL화
more..
// SHARED.dll만들기
// 공유 메모리는 반드시 초기화 해야 한다.,!!!!!!!!!!!!!!
#pragma data_seg("SHARED")
char buf[1024] = { 0 };
#pragma data_seg()
#pragma comment( linker, "/section:SHARED,RWS" )
/////////////////////////////////////////////////////
extern "C" __declspec(dllexport) void SetData(char* s)
{
strcpy( buf, s );
}
extern "C" __declspec(dllexport) void GetData(char* s)
{
strcpy( s, buf );
}
/////////////////////////////////////////////////////////////////////////////
// A.cpp
typedef void(*F)(char*);
int main()
{
HMODULE hDll = LoadLibrary( "SHARED.dll" );
F SetData = (F)GetProcAddress( hDll, "SetData" );
F GetData = (F)GetProcAddress( hDll, "GetData" );
HANDLE hEvent = CreateEvent( 0, 0, 0, "e" );
HANDLE hEvent2 = CreateEvent( 0, 0, TRUE, "e2" ); // 최초의 signal은 통과해라.
while( 1 )
{
char buf[256] = { 0 };
WaitForSingleObject( hEvent, INFINITE );
// DLL의 공유 버퍼에서 Data를 꺼낸다.
GetData( buf );
SetEvent( hEvent2 );
printf( "읽어온 data : %s\n", buf );
}
}
///////////////////////////////////////////////////////////////////////////
// B.cpp
typedef void(*F)(char*);
int main()
{
HMODULE hDll = LoadLibrary( "SHARED.dll" );
F SetData = (F)GetProcAddress( hDll, "SetData" );
F GetData = (F)GetProcAddress( hDll, "GetData" );
HANDLE hEvent = CreateEvent( 0, 0, 0, "e" );
HANDLE hEvent2 = CreateEvent( 0, 0, TRUE, "e2" ); // 최초의 signal은 통과해라.
while( 1 )
{
char buf[256] = { 0 };
gets( buf ); // 1줄입력
// 정말 가져 갔는지 확인한다.
WaitForSingleObject( hEvent2, INFINITE );
SetData( buf );
// 대기중인 스레드를 깨운다.
SetEvent( hEvent );
}
}
// 공유 메모리는 반드시 초기화 해야 한다.,!!!!!!!!!!!!!!
#pragma data_seg("SHARED")
char buf[1024] = { 0 };
#pragma data_seg()
#pragma comment( linker, "/section:SHARED,RWS" )
/////////////////////////////////////////////////////
extern "C" __declspec(dllexport) void SetData(char* s)
{
strcpy( buf, s );
}
extern "C" __declspec(dllexport) void GetData(char* s)
{
strcpy( s, buf );
}
/////////////////////////////////////////////////////////////////////////////
// A.cpp
typedef void(*F)(char*);
int main()
{
HMODULE hDll = LoadLibrary( "SHARED.dll" );
F SetData = (F)GetProcAddress( hDll, "SetData" );
F GetData = (F)GetProcAddress( hDll, "GetData" );
HANDLE hEvent = CreateEvent( 0, 0, 0, "e" );
HANDLE hEvent2 = CreateEvent( 0, 0, TRUE, "e2" ); // 최초의 signal은 통과해라.
while( 1 )
{
char buf[256] = { 0 };
WaitForSingleObject( hEvent, INFINITE );
// DLL의 공유 버퍼에서 Data를 꺼낸다.
GetData( buf );
SetEvent( hEvent2 );
printf( "읽어온 data : %s\n", buf );
}
}
///////////////////////////////////////////////////////////////////////////
// B.cpp
typedef void(*F)(char*);
int main()
{
HMODULE hDll = LoadLibrary( "SHARED.dll" );
F SetData = (F)GetProcAddress( hDll, "SetData" );
F GetData = (F)GetProcAddress( hDll, "GetData" );
HANDLE hEvent = CreateEvent( 0, 0, 0, "e" );
HANDLE hEvent2 = CreateEvent( 0, 0, TRUE, "e2" ); // 최초의 signal은 통과해라.
while( 1 )
{
char buf[256] = { 0 };
gets( buf ); // 1줄입력
// 정말 가져 갔는지 확인한다.
WaitForSingleObject( hEvent2, INFINITE );
SetData( buf );
// 대기중인 스레드를 깨운다.
SetEvent( hEvent );
}
}