1. 스레드!!!
- 개념 ( 윈도우는 스레드기반으로 돌아간다. )
1) 가상주소 => 페이지테이블 => 물리주소
2) CR3 : 페이지 테이블의 주소
3) CPU는 10ms씩 인터럽트가 발생하여 Context Switching 이 발생
4) 인터럽트 Handler 는 스케줄러 담당한다. 두개이상의 프로세스가 동시에 실행되도록 한다.
5) 퀀텀Time : 20ms 최소의 실행시간을 보장해준다.
6) 메시지Q는 GUI 요소를 갖는 윈도우만 가지고 있다.
7) GetMessage() 에서 message가 없다면 Context Switching 이 발생..
8) Sleep(0); 을 해서 강제로 C.W 발생..
9) 메모리 관리 : 프로세스가 CR3를 가지고 있다.(ReadProcessMemory는 CR3의 주소값을 참조.)
10) 실행흐름 : 스레드가 관리한다.
- 함수
1) CreateThread, CreateRemoteThread ( 다른프로세스에 스레드를 생성 ), _beginThreadex
- 주스레드에서(main()) 스레드A를 생성하게 되면 ETHREAD에 1MB의 스택영역이 생성된다.
- 주스레에서 main리턴하게 되면 프로세스가 종료되고, ExitThread를 해주면 주스레드만 종료된다.
- 다른 스레드의 종료를 대기해줘야 할때 ( WaitForxxx )
1) WaitForSingleObject - 스레드구조체의 staterk signal 상태가 되기를 기다리게 된다.
- WaitForSingleObject 의 원리
1) dt nt!_KEVENT, dt nt!_KTHREAD 에는 공통적으로 _DISPATCHER_HEADER 가 있다.
2. MulitiThread
- CriticalSection 영역을 ThreadSafe 하기 위해선 CRITICAL_SECTION을 사용한다.
- Serializetion( 직렬화 ) : 2차선 -> 1차선으로 바꿔서 스레드 한개만 활동하게 한다.
- 듀얼 코어에서는 자러가는시간 1000ms 과 깨어나는 시간 100ms 라면 깨어나는 Thread가 계속 실행될 수 있다. 그래서 SpinCounter 500ms 정도로 설정하여 CS에 진입을 재시도 하게 한다.
3. 원자 연산 ( Atomic Operation )
- asm으로 원잔연산을 보장 해주기 위해선 inc 라는 명령어를 사용한다.
- 듀얼코어에서는 lock 이라는 접두어를 붙여줘야 한다.
- InterlockIncrement : lock inc x 를 구현해 놓은 함수이다...
- 개념 ( 윈도우는 스레드기반으로 돌아간다. )
1) 가상주소 => 페이지테이블 => 물리주소
2) CR3 : 페이지 테이블의 주소
3) CPU는 10ms씩 인터럽트가 발생하여 Context Switching 이 발생
4) 인터럽트 Handler 는 스케줄러 담당한다. 두개이상의 프로세스가 동시에 실행되도록 한다.
5) 퀀텀Time : 20ms 최소의 실행시간을 보장해준다.
6) 메시지Q는 GUI 요소를 갖는 윈도우만 가지고 있다.
7) GetMessage() 에서 message가 없다면 Context Switching 이 발생..
8) Sleep(0); 을 해서 강제로 C.W 발생..
9) 메모리 관리 : 프로세스가 CR3를 가지고 있다.(ReadProcessMemory는 CR3의 주소값을 참조.)
10) 실행흐름 : 스레드가 관리한다.
- 함수
1) CreateThread, CreateRemoteThread ( 다른프로세스에 스레드를 생성 ), _beginThreadex
- 주스레드에서(main()) 스레드A를 생성하게 되면 ETHREAD에 1MB의 스택영역이 생성된다.
- 주스레에서 main리턴하게 되면 프로세스가 종료되고, ExitThread를 해주면 주스레드만 종료된다.
- 다른 스레드의 종료를 대기해줘야 할때 ( WaitForxxx )
1) WaitForSingleObject - 스레드구조체의 staterk signal 상태가 되기를 기다리게 된다.
- WaitForSingleObject 의 원리
1) dt nt!_KEVENT, dt nt!_KTHREAD 에는 공통적으로 _DISPATCHER_HEADER 가 있다.
+0x000 Header : _DISPATCHER_HEADER
///////////////////////////////////////////////////////////////////////////////////////
+0x000 Type : UChar
+0x001 Absolute : UChar
+0x002 Size : UChar
+0x003 Inserted : UChar
+0x004 SignalState : Int4B <= 모든 KO는 이를 가지고 있다. 실행과 대기를 위해서~~
+0x008 WaitListHead : _LIST_ENTRY
///////////////////////////////////////////////////////////////////////////////////////
+0x000 Type : UChar
+0x001 Absolute : UChar
+0x002 Size : UChar
+0x003 Inserted : UChar
+0x004 SignalState : Int4B <= 모든 KO는 이를 가지고 있다. 실행과 대기를 위해서~~
+0x008 WaitListHead : _LIST_ENTRY
2. MulitiThread
DWORD CALLBACK foo( void* p )
{
int x; // TLS 내에 생긴다.(Thread Local Storage) 지역변수는 Thread Safe
static int y; // 프로세스의 static 공간에 생긴다. 스레드에 안전하지 않다. CriticalSection
return 0;
}
{
int x; // TLS 내에 생긴다.(Thread Local Storage) 지역변수는 Thread Safe
static int y; // 프로세스의 static 공간에 생긴다. 스레드에 안전하지 않다. CriticalSection
return 0;
}
- CriticalSection 영역을 ThreadSafe 하기 위해선 CRITICAL_SECTION을 사용한다.
- Serializetion( 직렬화 ) : 2차선 -> 1차선으로 바꿔서 스레드 한개만 활동하게 한다.
- 듀얼 코어에서는 자러가는시간 1000ms 과 깨어나는 시간 100ms 라면 깨어나는 Thread가 계속 실행될 수 있다. 그래서 SpinCounter 500ms 정도로 설정하여 CS에 진입을 재시도 하게 한다.
3. 원자 연산 ( Atomic Operation )
DWORD CALLBACK foo( void* p )
{
for ( int i = 0; i < 10000; ++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;
}
{
for ( int i = 0; i < 10000; ++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;
}
- asm으로 원잔연산을 보장 해주기 위해선 inc 라는 명령어를 사용한다.
- 듀얼코어에서는 lock 이라는 접두어를 붙여줘야 한다.
- InterlockIncrement : lock inc x 를 구현해 놓은 함수이다...
TIP : 함수의 어셈 코드 보기
HMODULE hdll = GetModuleHandle( " xxx.dll " ); // 함수가 포함된 dll
void* p = (void*) GetProcAddress( hdll, "함수명" );
printf( "%p\n", p );
=> 함수의 dll에서의 주소(p)를 디스어셈블리창에서 찾아보면 나온다..
HMODULE hdll = GetModuleHandle( " xxx.dll " ); // 함수가 포함된 dll
void* p = (void*) GetProcAddress( hdll, "함수명" );
printf( "%p\n", p );
=> 함수의 dll에서의 주소(p)를 디스어셈블리창에서 찾아보면 나온다..