1. Debug 용 에러출력매크로( TRACE, ASSERT, VERIFY )
2. CreateThread 와 종료대기
3. 멀티 스레드와 동기화
4. CrtiticalSection 의 Leave 보장..
5. Atomic( 저수준 단계에서 원자연산 보장!! )
LONG x = 0;
DWORD CALLBACK foo( void* p )
{
for ( int i = 0; i < 1000000; ++i )
{
// COM 기반 기술에서 자주 사용한다.!!!!!!!
InterlockedExchange( &x, 0 ); // x = 0
InterlockedExchangeAdd( &x, 5 ); // x = x+5;
InterlockedDecrement( &x ); // x -= 1;
InterlockedIncrement( &x ); // lock inc x 로 구현된 함수. x += 1
//x = x+1; // 보장받지 못한다.
__asm
{
//lock inc x // inc 는 원자 연산이다. 즉, inc 실행중 절대 Context Switch가 발생안함.
// mov eax, x
// add eax, 1
// mov x, eax
}
}
return 0;
}
int main()
{
HMODULE hDll = GetModuleHandle( "Kernel32.dll" );
void* p = (void*)GetProcAddress( hDll, "GetLastError" );
printf("%p\n", p);
GetLastError();
HANDLE h[3];
h[0] = CreateThread( 0, 0, foo, 0, 0, 0 );
h[1] = CreateThread( 0, 0, foo, 0, 0, 0 );
h[2] = CreateThread( 0, 0, foo, 0, 0, 0 );
WaitForMultipleObjects( 3, h, TRUE, INFINITE );
CloseHandle( h[0] );
CloseHandle( h[1] );
CloseHandle( h[2] );
printf( "결과 : %d\n", x );
}
6. ReadProcessMemory
more..
// TRACE, ASSERT, VERIFY 에 대한 이야기
// TRACE : 디버그 메세지 출력
// ASSERT : 개발 중에만 식의 유효를 판단하고 실제 빌드에서는 제거 하고 싶을 때.
// VERIFY : 디버그모드에서 에러 check, Release 모드에서는 기능만 수행.
#ifdef _DEBUG
#define TRACE(x) printf(x)
#else
#define TRACE(x)
#endif
#ifdef _DEBUG
#define ASSERT(x) if ( !(x) ) { printf("Assert Failed = %s", #x); }
#else
#define ASSERT(x)
#endif
#ifdef _DEBUG
#define VERIFY(x) ASSERT(x)
#else
#define VERIFY(x) x
#endif
bool goo()
{
printf("goo\n");
return true;
}
void foo( int age )
{
// 주로 인자의 유효성을 확인하기 위해 자주 사용한다.
ASSERT( age > 0 );
// 나이 만큼 메모리 할당을 한다.
int* p = new int[age];
}
int main()
{
//TRACE( "디버그 메시지\n" );
//foo( -1 );
// 리턴값이 false라면 에러를 출력한다.!!(Debug 모드에서만..)
VERIFY( goo() ); // 디버그라면 : ASSERT( goo() )
}
// TRACE : 디버그 메세지 출력
// ASSERT : 개발 중에만 식의 유효를 판단하고 실제 빌드에서는 제거 하고 싶을 때.
// VERIFY : 디버그모드에서 에러 check, Release 모드에서는 기능만 수행.
#ifdef _DEBUG
#define TRACE(x) printf(x)
#else
#define TRACE(x)
#endif
#ifdef _DEBUG
#define ASSERT(x) if ( !(x) ) { printf("Assert Failed = %s", #x); }
#else
#define ASSERT(x)
#endif
#ifdef _DEBUG
#define VERIFY(x) ASSERT(x)
#else
#define VERIFY(x) x
#endif
bool goo()
{
printf("goo\n");
return true;
}
void foo( int age )
{
// 주로 인자의 유효성을 확인하기 위해 자주 사용한다.
ASSERT( age > 0 );
// 나이 만큼 메모리 할당을 한다.
int* p = new int[age];
}
int main()
{
//TRACE( "디버그 메시지\n" );
//foo( -1 );
// 리턴값이 false라면 에러를 출력한다.!!(Debug 모드에서만..)
VERIFY( goo() ); // 디버그라면 : ASSERT( goo() )
}
2. CreateThread 와 종료대기
more..
void Delay() { for( int i = 0; i < 10000000; ++i); }
BOOL bWait = TRUE;
// win32 스레드 함수의 모양
DWORD CALLBACK foo( void* p )
{
char* n = (char*)p;
int x = 0;
for ( int i = 0; i < 1000; ++i )
{
x = 100; Delay();
x = x + 1; Delay();
printf( "%s : %d\n", n, x );
}
printf( "%s Finish\n", n );
bWait = FALSE;
return 0;
}
int main()
{
// foo( "A" ); // 호출
DWORD tid;
HANDLE h1 = CreateThread(
0, // 보안속성
0, // stack 크기
foo, // 스레드로 실행할 함수
"A", // 인자
0, // 우선순위 | 플래그
&tid // 생성된 스레드 ID를 담아올 변수(win2000 에서는 0 가능)
);
WaitForSingleObject( h1, INFINITE );
// while( bWait ); // 최악의 코드.. 할일이 없는데 CPU를 사용한다.
// printf("main....\n");
// ExitThread(0); // 현재 스레드(주스레드)만 종료한다. - 프로세스 종료가 아니다.
}
BOOL bWait = TRUE;
// win32 스레드 함수의 모양
DWORD CALLBACK foo( void* p )
{
char* n = (char*)p;
int x = 0;
for ( int i = 0; i < 1000; ++i )
{
x = 100; Delay();
x = x + 1; Delay();
printf( "%s : %d\n", n, x );
}
printf( "%s Finish\n", n );
bWait = FALSE;
return 0;
}
int main()
{
// foo( "A" ); // 호출
DWORD tid;
HANDLE h1 = CreateThread(
0, // 보안속성
0, // stack 크기
foo, // 스레드로 실행할 함수
"A", // 인자
0, // 우선순위 | 플래그
&tid // 생성된 스레드 ID를 담아올 변수(win2000 에서는 0 가능)
);
WaitForSingleObject( h1, INFINITE );
// while( bWait ); // 최악의 코드.. 할일이 없는데 CPU를 사용한다.
// printf("main....\n");
// ExitThread(0); // 현재 스레드(주스레드)만 종료한다. - 프로세스 종료가 아니다.
}
3. 멀티 스레드와 동기화
more..
void Delay() { for( int i = 0; i < 10000000; ++i); }
DWORD CALLBACK foo( void* p )
{
char* n = (char*)p;
static int x = 0;
for ( int i = 0; i < 20; ++i )
{
//EnterCriticalSection( &cs ); // cs영역에 들어가는 것. cs는 1개의 스레드만 들어간다.
if( TryEnterCriticalSection( &cs ) ) // win2000 전용함수
{
//////////////////////////////////////
x = 100; Delay();
x = x + 1; Delay();
printf( "%s : %d\n", n, x );
//////////////////////////////////////
LeaveCriticalSection( &cs ); // cs영역에서 나온다.
}
else
{
// Critical Section에 들어가지 못할 경우에 할일..
printf("%s : CriticalSection에 들어 갈수 없습니다.\n", n );
--i;
}
}
printf( "%s Finish\n", n );
return 0;
}
int main()
{
InitializeCriticalSection( &cs );
HANDLE h1 = CreateThread( 0, 0, foo, "A", 0, 0 );
HANDLE h2 = CreateThread( 0, 0, foo, "\tB", 0, 0 );
// 64개 까지 대기 가능한 함수.!! - MFC에서 CMultiLock 클래스가 아래 함수의 기능을 클래스화 한다.
HANDLE h[2] = { h1, h2 };
WaitForMultipleObjects( 2, h, TRUE, INFINITE );
CloseHandle( h1 );
CloseHandle( h2 );
DeleteCriticalSection( &cs );
}
DWORD CALLBACK foo( void* p )
{
char* n = (char*)p;
static int x = 0;
for ( int i = 0; i < 20; ++i )
{
//EnterCriticalSection( &cs ); // cs영역에 들어가는 것. cs는 1개의 스레드만 들어간다.
if( TryEnterCriticalSection( &cs ) ) // win2000 전용함수
{
//////////////////////////////////////
x = 100; Delay();
x = x + 1; Delay();
printf( "%s : %d\n", n, x );
//////////////////////////////////////
LeaveCriticalSection( &cs ); // cs영역에서 나온다.
}
else
{
// Critical Section에 들어가지 못할 경우에 할일..
printf("%s : CriticalSection에 들어 갈수 없습니다.\n", n );
--i;
}
}
printf( "%s Finish\n", n );
return 0;
}
int main()
{
InitializeCriticalSection( &cs );
HANDLE h1 = CreateThread( 0, 0, foo, "A", 0, 0 );
HANDLE h2 = CreateThread( 0, 0, foo, "\tB", 0, 0 );
// 64개 까지 대기 가능한 함수.!! - MFC에서 CMultiLock 클래스가 아래 함수의 기능을 클래스화 한다.
HANDLE h[2] = { h1, h2 };
WaitForMultipleObjects( 2, h, TRUE, INFINITE );
CloseHandle( h1 );
CloseHandle( h2 );
DeleteCriticalSection( &cs );
}
4. CrtiticalSection 의 Leave 보장..
more..
// 예외를 대비하는 새로운 클래스 : MFC 배울때. CSingleLock과 CMultiLock 헷갈리지 마세요.
class CsyncObject
{
public:
virtual void Lock() {}
virtual void UnLock() {}
};
class CCriticalSection : public CsyncObject
{
CRITICAL_SECTION m_cs;
public:
CCriticalSection() { InitializeCriticalSection(&m_cs); }
~CCriticalSection() { DeleteCriticalSection(&m_cs); }
void Lock() { EnterCriticalSection(&m_cs); }
void UnLock() { LeaveCriticalSection(&m_cs); }
};
class CSingleLock
{
CsyncObject* p;
public:
CSingleLock( CsyncObject* _p ) : p(_p) {}
void Lock() { p->Lock(); }
void UnLock() { p->UnLock(); }
};
CCriticalSection cs;
UINT CALLBACK goo( void* p )
{
CSingleLock slock(&cs);
slock.Lock();
// 그런데.. 여기서 C++ 예외가 발생.
// 어떻게 될까??
throw 1;
slock.UnLock();
}
class CsyncObject
{
public:
virtual void Lock() {}
virtual void UnLock() {}
};
class CCriticalSection : public CsyncObject
{
CRITICAL_SECTION m_cs;
public:
CCriticalSection() { InitializeCriticalSection(&m_cs); }
~CCriticalSection() { DeleteCriticalSection(&m_cs); }
void Lock() { EnterCriticalSection(&m_cs); }
void UnLock() { LeaveCriticalSection(&m_cs); }
};
class CSingleLock
{
CsyncObject* p;
public:
CSingleLock( CsyncObject* _p ) : p(_p) {}
void Lock() { p->Lock(); }
void UnLock() { p->UnLock(); }
};
CCriticalSection cs;
UINT CALLBACK goo( void* p )
{
CSingleLock slock(&cs);
slock.Lock();
// 그런데.. 여기서 C++ 예외가 발생.
// 어떻게 될까??
throw 1;
slock.UnLock();
}
5. Atomic( 저수준 단계에서 원자연산 보장!! )
more..
LONG x = 0;
DWORD CALLBACK foo( void* p )
{
for ( int i = 0; i < 1000000; ++i )
{
// COM 기반 기술에서 자주 사용한다.!!!!!!!
InterlockedExchange( &x, 0 ); // x = 0
InterlockedExchangeAdd( &x, 5 ); // x = x+5;
InterlockedDecrement( &x ); // x -= 1;
InterlockedIncrement( &x ); // lock inc x 로 구현된 함수. x += 1
//x = x+1; // 보장받지 못한다.
__asm
{
//lock inc x // inc 는 원자 연산이다. 즉, inc 실행중 절대 Context Switch가 발생안함.
// mov eax, x
// add eax, 1
// mov x, eax
}
}
return 0;
}
int main()
{
HMODULE hDll = GetModuleHandle( "Kernel32.dll" );
void* p = (void*)GetProcAddress( hDll, "GetLastError" );
printf("%p\n", p);
GetLastError();
HANDLE h[3];
h[0] = CreateThread( 0, 0, foo, 0, 0, 0 );
h[1] = CreateThread( 0, 0, foo, 0, 0, 0 );
h[2] = CreateThread( 0, 0, foo, 0, 0, 0 );
WaitForMultipleObjects( 3, h, TRUE, INFINITE );
CloseHandle( h[0] );
CloseHandle( h[1] );
CloseHandle( h[2] );
printf( "결과 : %d\n", x );
}
6. ReadProcessMemory
more..
// A.cpp 메모리에 변수하나를 올린다.
int main()
{
char passwd[256] = { 0 };
printf( "PID : %d\n", GetCurrentProcessId() );
printf( "passwd 주소 : %p\n", passwd );
while ( 1 )
{
printf( "암호를 입력하세요. >>" );
scanf( "%s", passwd );
}
}
// B.cpp A.exe의 메모리 읽어오기..
int main()
{
DWORD pid = xxxx; // A의 PID를 넣으세요.
char* addr = (char*)0x0012FE60; // passwd의 주소를 넣으세요.
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );
while ( 1 )
{
char buf[256] = { 0 };
DWORD len;
ReadProcessMemory( hProcess, addr, buf, 256, &len ); // 핵심!!
printf( "읽어온 data : %s\n", buf );
getch();
}
}
int main()
{
char passwd[256] = { 0 };
printf( "PID : %d\n", GetCurrentProcessId() );
printf( "passwd 주소 : %p\n", passwd );
while ( 1 )
{
printf( "암호를 입력하세요. >>" );
scanf( "%s", passwd );
}
}
// B.cpp A.exe의 메모리 읽어오기..
int main()
{
DWORD pid = xxxx; // A의 PID를 넣으세요.
char* addr = (char*)0x0012FE60; // passwd의 주소를 넣으세요.
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, 0, pid );
while ( 1 )
{
char buf[256] = { 0 };
DWORD len;
ReadProcessMemory( hProcess, addr, buf, 256, &len ); // 핵심!!
printf( "읽어온 data : %s\n", buf );
getch();
}
}