10.9(화) 실습-1

2007/10/14 14:36

1. Debug 용 에러출력매크로( TRACE, ASSERT, VERIFY )
[ more.. | less.. ]
// 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() )
}

2. CreateThread 와 종료대기
[ more.. | less.. ]
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);    // 현재 스레드(주스레드)만 종료한다. - 프로세스 종료가 아니다.
}

3. 멀티 스레드와 동기화
[ more.. | less.. ]
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 );
}

4. CrtiticalSection 의 Leave 보장..
[ more.. | less.. ]
// 예외를 대비하는 새로운 클래스 : 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();
}

5. Atomic( 저수준 단계에서 원자연산 보장!! )
[ more.. | less.. ]

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.. | less.. ]
// 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();
    }
}

Tags

System, 실습