9번 문제 : 송영균 이병의 제대일을 구하세요.





문제풀이------------------------------------------------------------------------------------------------

문제 풀이 보기

Posted by Dakuo


올리디버거 창들 중에 Executable Modules 창이 있다.

현재 불러온 프로세스에서 실행중인 모듈들을 보여준다.

한 프로그램에서 여러개의 모듈(ex. DLL 등)을 사용할 경우

올리디버거는 하나의 모듈만을 트레싱할 수 있기 때문에 제대로 분석할수가 없다.

따라서 Executable Modules 창을 이용해 실행 가능한 모듈을 골라서 중요한 코드에

BreakPoint 를 걸어놓음으로써 해당 코드가 실행될 때에 제어권을 올리디버거로 받아 문제를 해결할 수 있다.


일단 해당문제를 실행시켜보자.

Ezbeat 문제 패스워드 찾기
올바른 패스워를 찾으시오!
난이도 : ★☆☆☆☆

위의 메시지 박스가 뜨며 확인을 누르면

콘솔창 하나가 뜨며 Input Password : 를 입력하라고 뜬다.


올리디버거로 프로그램을 오픈한다.

메시지 박스가 뜨므로 back to user mode 를 이용한다.

Run(F9)을 한다. 메시지 박스가 뜨면 pause(F12)를 한다.

back to user mode(Alt + F9)를 한 후 확인창을 누른다.


그러면 다음과 같은 코드로 이동한다.

00401149  |.  57            PUSH EDI                                    ; /Style
0040114A  |.  68 5CD34000   PUSH CrackMe_.0040D35C       ; |E
0040114F  |.  68 80D34000   PUSH CrackMe_.0040D380        ; |Text = "올바른 패스워드를 찾으시오!.
                                                                                     난이도 : ★☆☆☆☆"
00401154  |.  51            PUSH ECX                                  ; |hOwner
00401155  |.  FF15 4CC14000 CALL DWORD PTR DS:[<&USER32.MessageBoxW>>; \MessageBoxW
0040115B  |.  6A 03         PUSH 3                                     ; /ShowState = SW_SHOWMAXIMIZED
0040115D  |.  68 40D34000   PUSH CrackMe_.0040D340        ; |c:\solve.exe
00401162  |.  FF15 18C04000 CALL DWORD PTR DS:[<&KERNEL32.WinExec>]  ; \WinExec

위의 코드를 보면 WinExec 라는 WinAPI 가 보인다.

이 WinExec 함수는 CreateProcess 와 같이 프로세스를 생성하는 함수이다.

따라서 위의 3줄을 해석해보면 

WinExec 함수를 사용하여 최대창으로(SW_SHOWMAXIMIZED) c:\solve.exe 를 실행시켜라라는 뜻이다.

즉, 우리는 분석하던 CrackMe_2.exe 프로세스가 아니라 solve.exe 프로세스를 분석해야 한다.


따라서 WinExec 함수까지 실행을 한후에 solve.exe 가 실행되면

Attach 로 solve.exe 프로세스를 올리디버거로 불러온다.

E창을 눌러 Executable Modules 창을 연다.


맨 위의 solve 를 클릭한다. 실행영역에 올라온 코드들이다.

조금 아래로 가서 살펴보면

0040105C   .  68 3CD34000   PUSH solve.0040D33C                      ;  ASCII "Input Password : "
00401061   .  E8 28020000   CALL solve.0040128E
00401066   .  83C4 08       ADD ESP,8
00401069   .  E8 2F030000   CALL solve.0040139D
0040106E   .  50            PUSH EAX
0040106F   .  6A 63         PUSH 63
00401071   .  8D55 90       LEA EDX,DWORD PTR SS:[EBP-70]
00401074   .  52            PUSH EDX
00401075   .  E8 69070000   CALL solve.004017E3
0040107A   .  83C4 0C       ADD ESP,0C
0040107D   .  6A 0E         PUSH 0E

정답으로 보이는 값이 보인다.

입력하면 congratulation~!   가 출력된다.

Posted by Dakuo

메모리 접근 동기화 :

1. 크리티컬 섹션(Critical Section) 기반의 동기화 - 유저 모드


2. 인터락 함수(Interlocked Family Of Function) 기반의 동기화 - 유저 모드


3. 뮤텍스(Mutex) 기반의 동기화 - 커널 모드


4. 세마포어(Semaphore) 기반의 동기화 - 커널 모드


5. 이름있는 뮤텍스(Named Mutex) 기반의 프로세스 동기화 - 커널 모드





실행 순서의 동기화 :

1. 이벤트 기반의 동기화


2. 이벤트 + 뮤텍스 동기화

Posted by Dakuo

쓰레드 동기화 : 쓰레드 간의 질서가 잘 지켜지고 있음을 의미


쓰레드 동기화의 방법 :

유저 모드 동기화 :
 
동기화가 진행되는 과정에서 커널 코드가 실행되지 않는다.

커널 모드로의 전환이 이뤄지지 않으므로 성능상에 이점이 있지만 기능상의 제한도 있다.


커널 모드 동기화 :
 
커널에서 제공하는 동기화 기능을 활용한다.(유저 모드에서 제공하지 못하는 기능을 제공받을 수 있다)

커널 모드로의 전환으로 인해 성능이 저하된다.



두가지 관점에서의 쓰레드 동기화 :

메모리 접근에 대한 동기화 :

쓰레드들의 임계 영역 동시접근을 막아 동기화한다.

(참고 :

임계 영역(Critical Section) : 배타적 접근(한 순간에 하나의 쓰레드만 접근)이 요구되는

공유 리소스(전역변수와 같은)에 접근하는 코드 블록)

(예 :

쓰레드 A, B 가 전역변수 total 에 값을 변경한다.

이 경우 동시에 total 에 접근할 경우 문제가 생길수 있다.

따라서 total 을 변경하는 코드(임계 영역)에 하나의 쓰레드만 접근할 수 있도록 동기화한다)


동기화 기법 :

1. 크리티컬 섹션(Critical Section) 기반의 동기화 - 유저 모드

2. 인터락 함수(Interlocked Family Of Function) 기반의 동기화 - 유저 모드

3. 뮤텍스(Mutex) 기반의 동기화 - 커널 모드

4. 세마포어(Semaphore) 기반의 동기화 - 커널 모드

5. 이름있는 뮤텍스(Named Mutex) 기반의 프로세스 동기화 - 커널 모드



실행 순서의 동기화 :

메모리에 접근하는 쓰레드의 실행순서를 동기화한다.

(예 :

A 쓰레드는 입력을 받는다.

B 쓰레드는 입력받은 것을 출력한다.

그렇다면 A -> B 실행순서가 지켜지도록 동기화해야 한다)


동기화 기법 :

1. 이벤트(Event) 기반의 동기화 - 커널 모드

Posted by Dakuo

이벤트(Event) 기반 동기화 :

개념 :

생산자는 문자열을 생성한다(입력받는다), 소비자는 문자열을 소비한다(출력한다)

생산자가 문자열을 생성하고 나면, 이 상태를 감지한 소비자가 문자열을 가져가 소비한다.


이벤트 커널 오브젝트의 특성 :

1. 이벤트 커널 오브젝트는 파라미터에 의해 Signaled or Non-Signaled 상태로 생성된다.

2. 프로그래머의 요청에 의해 Signaled 상태가 된다.

3. 자동 리셋 모드 일시 WaitForSingleObject 함수 호출로 Signaled -> Non-Signaled 상태로 변경된다.
    수동 리셋 모드 일시 추가로 ResetEvent 함수를 사용한다.


사용법 :

HANDLE CreateEvent(
          LPSECURITY_ATTRIBUTES lpEventAttributes, // 보안속성
          BOOL bManualReset,  // TRUE : 수동 리셋 모드(Manual-Reset)
                                           // FALSE : 자동 리셋 모드(Auto-Reset)
          BOOL bInitialState,       // TRUE : Signaled 상태의 이벤트 커널 오브젝트 생성
                                           // FALSE : Non-Signaled 상태의 이벤트 커널 오브젝트 생성
          LPCTSTR lpName       // 이벤트 커널 오브젝트의 이름(NULL : 이름없는 이벤트 커널 오브젝트)
);
 
BOOL ResetEvent(
          HANDLE hEvent  // 이벤트 커널 오브젝트의 핸들 ( Non-Signaled 상태가 된다)
);

BOOL SetEvent(
          HANDLE hEvent  // 이벤트 커널 오브젝트의 핸들 (Signaled 상태가 된다)
);

CloseHandle() 함수로 핸들을 반환하여 끝낸다.



이벤트(Event) + 뮤텍스(Mutex) :

개념 :

생산자 하나에 소비자가 둘이다.

생산자가 생산하고 나면 소비자 둘은 동기화를 통해 소비해야 한다.


사용법 :

1. 생산자와 소비자간의 이벤트 기반 동기화를 한다. (실행순서 동기화)

2. 소비자간의 임계 영역에 뮤텍스(임계 영역 동기화 기법)로 동기화 한다. (메모리 접근 동기화)

Posted by Dakuo
1. 크리티컬 섹션 기반의 동기화(유저 모드) :

개념 :

열쇠(Critical Section)를 생성한다.

쓰레드가 임계 영역에 접근하기 위해서는 열쇠를 얻어야 한다.

열쇠를 얻어 임계 영역에 접근한 쓰레드는 일을 마친후 다음 쓰레드를 위해 열쇠를 반환한다.


사용법 :

CRITICAL_SECTION gCriticalSection;              // 열쇠를 생성한다
                   // 크리티컬 섹션 오브젝트 선언후에는 반드시 초기화 해야한다.
void InitializeCriticalSection(                           // 크리티컬 섹션 오브젝트 초기화 함수   
        LPCRITICAL_SECTION lpCriticalSection  // 초기화 하려는 크리티컬 섹션 오브젝트의 주소값
);

void EnterCriticalSection(
        LPCRITICAL_SECTION lpCriticalSection // 획득하려는 크리티컬 섹션 오브젝트의 주소값
);

열쇠(크리티컬 섹션 오브젝트)를 획득한다.

다른 쓰레드가 열쇠를 소유한 상태이면 반환할 때까지 블로킹된다.

열쇠가 반환되면 블로킹 상태에서 빠져나와 열쇠를 획득하여 임계 영역에 접근한다.
(이때 쓰레드가 크리티컬 섹션 오브젝트를 획득했다고 한다)

void LeaveCriticalSection(
        LPCRITICAL_SECTION lpCriticalSection // 반환하려는 크리티컬 섹션 오브젝트의 주소값
);

임계 영역을 빠져 나와 열쇠를 반환한다.

호출이 완료되면 크리티컬 섹션 오브젝트를 반환했다고 표현한다

만약 EnterCriticalSection 을 호출하고 블로킹 상태에 놓인 쓰레드가 있다면

이 함수 호출로 인해 블로킹 상태에서 빠져 나와 열쇠를 획득해 임계 영역에 접근한다.

void DeleteCriticalSection(
        LPCRITICAL_SECTION lpCriticalSection // 리소스 해제할 크리티컬 섹션 오브젝트의 주소값
);

크리티컬 섹션 오브젝트 초기화 함수가 호출되는 과정에서 할당된 리소스들을 반환한다.

(참고 : 임계 영역 접근 동기화를 위하여 열쇠(CriticalSection)을 사용한다.

하지만 여러 쓰레드들이 이 열쇠를 획득하려 하면(EnterCriticalSection 함수 호출) 어떻게 될까?

이 함수에 대해서도 동기화를 해야 하지 않을까?

답은 '필요없다' 이다.

이 함수는 컨텍스트 스위칭을 막으므로 동기화 해줄 필요가 없다)



2. 인터락 함수(Interlocked Family Of Function) 기반의 동기화(유저 모드) :

개념 :

전역변수 하나의 접근방식을 동기화 할때 사용한다.

내부적으로 한 순간에 하나의 쓰레드만 실행되도록 동기화 되어 있다.(원자적 접근을 보장한다)

(원자적 접근(Atomic Access) : 한순간에 하나의 쓰레드만 접근)


사용법 :

LONG InterlockedIncrement(
        LONG volatile *Addend       // 값을 하나 증가시킬 32비트 변수의 주소값
);

LONG InterlockedDecrement(
        LONG volatile *Addend       // 값을 하나 감소시킬 32비트 변수의 주소값
);

(참고 : 이외에도 MS 에서는 다양한 인터락 함수들을 제공한다. MSDN 을 참조하자

volatile 의미 :

1) 최적화를 수행하지 마라.   // 해당 소스 그대로 컴파일 된다.
(a=1, a=2, a=3  최적화 컴파일->  a=3,      a=1, a=2, a=3  컴파일->  a=1, a=2, a=3)

2) 메모리에 직접 연산하라.   // 해당 데이터는 캐시되지 않고 데이터 전송이 바로 이뤄진다)



3. 뮤텍스(Mutex) 기반의 동기화(커널 모드) :

개념 :

크리티컬 섹션 오브젝트와 똑같다.(대상이 CriticalSection -> 뮤텍스)


뮤텍스 커널 오브젝트의 상태 :

Non-Signaled : 뮤텍스가 쓰레드에 의해 획득되어 있을 때

Signaled : 뮤텍스가 쓰레드에 의해 획득이 가능할 때


사용법 :

HANDLE CreateMutex(
         LPSECURITY_ATTRIBUTES lpMutexAttributes, // 뮤텍스 보안속성
         BOOL bInitialOwner,  // TURE : 뮤텍스를 생성하는 쓰레드가 먼저 기회를 얻는다.
                                        // FALSE : 뮤텍스를 먼저 획득하는 쓰레드가 기회를 얻는다.
         LPCTSTR lpName     // 뮤텍스에 이름을 붙여주기 위해 사용한다.(NULL 이 아닐경우 NamedMutex)
);

뮤텍스는 획득 가능할 때 Signaled 상태이므로

WaitForSingleObject 함수로 뮤텍스를 획득한다.

함수를 호출하고 나면 Signaled -> Non-Signaled 상태로 자동 변경된다.

BOOL ReleaseMutex(
         HANDLE hMutex       // 반환할 뮤텍스의 핸들 (Non-Signlaed -> Signaled)
);


사용을 완전히 마친 뮤텍스는

CloseHandle() 함수를 사용하여 핸들을 반환한다.



4. 세마포어(Semaphore) 기반의 동기화(커널 모드) :

개념 :

세마포어는 뮤텍스 + 카운트(Count) 이다.

즉, 쓰레드의 메모리 동시접근을 지정한 갯수만큼 허용한다는 것이다.
(뮤텍스는 하나의 쓰레드만 가능하다)

세마포어는 lInitialCount 에 의해 초기 카운트가 결정된다.

임계 영역에 접근한 쓰레드가 생기면 카운트 -1 이 되고
임계 영역에서 빠져 나온 쓰레드가 생기면 카운트 +1 이 된다.

카운트 0 : Non-Signaled (획득 불가능한 상태)
카운트 1 이상 : Signaled (획득 가능한 상태)


사용법 :

HANDLE CreateSemaphore(
         LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  // 보안속성
         LONG lInitialCount,          // 임계 영역에 접근 가능한 쓰레드의 개수
         LONG lMaximumCount,   // 세마포어가 지닐수 있는 값의 최대 크기(1일경우 뮤텍스와 동일한 기능)
         LPCTSTR lpName           // 세마포어에 이름(NULL 아닐 경우 이름있는 세마포어(Named Semaphore)
);

WaitForSingleObject 함수로 임계영역에 접근한다(세마포어 카운트 -1)

BOOL ReleaseSemaphore(
         HANDLE hSemaphore,          // 반환하고자 하는 세마포어의 핸들
         LONG lReleaseCount,           // 증가시킬 카운트 값의 크기(세마포어 생성시 결정한
                                                                                            최대 카운트값을 넘길 경우 FALSE 반환)
         LPLONG lpPreviousCount      // 변경되기 전 세마포어 카운트 값을 저장할 변수(필요없다면 NULL)
);


사용을 완전히 마친 세마포어는

CloseHandle() 함수를 사용하여 핸들을 반환한다.



5. 이름있는 뮤텍스(or 세마포어) 기반의 프로세스 동기화(커널 모드) :

개념 :

뮤텍스와 세마포어를 생성할 때 이름을 붙여 줄수 있다.

이름이 붙여지면 서로 다른 프로세스에 존재하는 쓰레드들끼리의 동기화가 가능하다.

사용법 :

HANDLE OpenMutex(
         DWORD dwDesiredAccess,    // 이름 있는 뮤텍스로의 접근권한 (MUTEX_ALL_ACCESS 전달)
         BOOL bInheritHandle,            // 핸들의 상속 유무 결정 
         LPCTSTR lpName                // 얻고자 하는 핸들 정보의 커널 오브젝트 이름(핸들 테이블에 등록된다)
);


(추가 : 뮤텍스의 소유와 WAIT_ABANDONED

두 개의 쓰레드 A, B 와 뮤텍스 C가 존재한다.

쓰레드 A가 뮤텍스 C를 획득했다.

쓰레드 B는 쓰레드 A가 뮤텍스 C를 반환하기를 기다리고 있다.

이때 쓰레드 A가 미처 반환하지 못하고 종료되어 버렸다.

그러면 Windows 가 쓰레드의 상태와 뮤텍스의 상태를 예의 주시하다가 문제가 발생했음을 인식하고

쓰레드 A 대신에 뮤텍스 C를 반환하여 쓰레드 B 가 획득할수 있게 한다.

이때 쓰레드 B는 WAIT_ABANDONED 을 반환받는다.

참고로 뮤텍스는 뮤텍스를 획득한 쓰레드가 직접 반환하는 것이 원칙이지만 세마포어와 그 이외의 동기화 오브젝트는 획득한 쓰레드가 직접 반환하지 않더라도(누가 대신 반환해도) 문제가 되지 않는다)

'Windows > _System Programming' 카테고리의 다른 글

쓰레드(Thread) 동기화 개념  (0) 2010.03.04
쓰레드(Thread) 실행순서 동기화  (0) 2010.03.04
쓰레드(Thread) 메모리 접근 동기화  (0) 2010.03.04
쓰레드(Thread)의 생성과 소멸  (0) 2010.02.28
쓰레드(Thread)  (2) 2010.02.28
환경변수  (0) 2010.02.25
Posted by Dakuo

쓰레드 생성 :

HANDLE CreateThread(
     LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 보안속성(TRUE : 상속, NULL : 상속제외)
     SIZE_T dwStackSize,                                      // 쓰레드의 스택 크기
     LPTHREAD_START_ROUTINE lpStartAddress,    // 쓰레드로 동작하기 위한 함수(쓰레드 main)
                                                                          // 리턴타입 DWORD, 매개변수 타입 LPVOID(void*)
     LPVOID lpParameter,                                       // 쓰레드 함수에 전달할 인자 지정
     DWORD dwCreationFlags,                                // 쓰레드 생성 및 실행을 조절
     LPDWORD lpThreadId                                      // 쓰레드 ID를 전달받기 위한 변수의 주소값
);



쓰레드 소멸 :

1. return(일반적, 안정적) :

쓰레드 함수에서 return 은 쓰레드 종료

main 쓰레드의 return 은 프로세스 종료

쓰레드 함수의 return 값은 그 쓰레드의 커널 오브젝트에 저장된다.

리턴값 획득 :

BOOL GetExitCodeThread(
      HANDLE hThread,                 // 종료코드를 얻기 위한 쓰레드의 핸들
      LPDWORD lpExitCode            // 얻게 되는 종료코드를 저장할 메모리 주소
);


2. ExitThread(특정 위치에서 쓰레드의 실행을 종료) :

현재 실행 중인 쓰레드를 종료

VOID ExitThread(
      DWORD dwExitCode             // 커널 오브젝트에 등록되는 쓰레드 종료 코드를 지정
);                                             // GetExitCodeThread 함수를 통해 종료코드 획득 가능

이 함수를 사용하면 언제 어디서나 쓰레드를 종료 시킬수 있다.


(참고 : C++ 프로그래밍을 할때 주의해야 한다.

예를 들어 A, B 함수에 C++ 객체가 존재한다고 할때 C 함수에서 ExitThread 함수로 쓰레드를 종료할 경우
A, B 함수의 스택 프레임에 존재하는 소멸자가 호출되지 않아 메모리 유출 현상이 발생할 수도 있다.
return 문에 의한 쓰레드 종료가 가장 좋다)


3. TerminateThread(외부에서 쓰레드를 종료) :

강제종료 함수

따라서 종료에 필요한 여러 가지 일들을 처리하지 못하고 바로 종료된다.

BOOL TerminateThread(
      HANDLE hThread,                 // 강제 종료할 쓰레드의 핸들
      DWORD dwExitCode              // 종료할 쓰레드의 종료코드를 인자로 전달
);


4. 프로세스로부터 쓰레드 분리

쓰레드는 생성과 동시에 프로세스의 핸들 테이블에 그 핸들이 등록되므로 Usage Count 가 2가 된다.

따라서 쓰레드 생성시 얻은 핸들을 CloseHandle 로 반환하면 Usage Count = 1 이 된다.
 
쓰레드를 종료하면 Usage Count = 0 이 되어 쓰레드 커널 오브젝트가 소멸된다.



쓰레드의 성격과 특성 :

공유 영역 사용 :

ex)

total 을 전역변수로 선언했다. 따라서 모든 쓰레드는 공유 total 을 가지고 덧셈연산을 진행한다.

최종결과를 main 쓰레드가 참조한다.


동시접근의 문제점 :

위 ex) 에서 둘 이상의 쓰레드가 전역변수 total 에 동시접근할 경우 문제점이 생긴다.


컨텍스트 스위칭은 연중에도 빈번히 일어날 수 있기에 둘 이상의 쓰레드가 같은 메모리 영역을 동시에 참조하는 것은 문제를 발생시킨다.

따라서 멀티 쓰레드 기반의 쓰레드를 생성해야 한다.

uintptr_t _beginthreadex(   // CreateThread 함수와 파라미터 순서와 의미가 같다.(자료형과 리턴형의 차이가 있다)
         void *security,
         unsigned stack_size,
         unsigned (*start_address)(void *),
         void *arglist,
         unsigned initflag,
         unsigned *thrdaddr
); 

_beginthreadex 함수를 사용하면

쓰레드 함수에 여러 파라미터를 전달할 수 있다.

각각의 쓰레드를 위해서 독립적인 메모리 블록을 할당한다.
(스택 공간 + 고유한 레지스터 값 + 현재 명령 주소)    // CreatThread 함수 (스택 공간)

따라서 return 과 endthreadex 함수를 사용하여 할당한 메모리를 해제해야 한다.

void _endthreadex(unsigned retval);  // ExitThread 함수와 동일



쓰레드의 상태 컨트롤 :

쓰레드의 상태 변화(Suspend & Resume) : // 프로세스 상태 변화와 개념이 같다.
                                                            // http://dakuo.tistory.com/entry/프로세스의-생성과-소멸

쓰레드의 커널 오브젝트 멤버 Suspend Count 는 쓰레드의 상태를 나타낸다.

Suspend Count = 0 : 현재 실행중인 쓰레드(Ready)

Suspend Count > 0 : Block 상태

DWORD SuspendThread(
        HANDLE hThread          // Suspend Count++ 할 쓰레드의 핸들
);

DWORD ResumeThread(
        HANDLE hThread          // Suspend Count-- 할 쓰레드의 핸들
);

이 함수들은 변경되기 이전에 Suspend Count 를 리턴한다.


쓰레드의 우선순위 컨트롤 :

프로세스의 우선순위는 기존 우선순위라고 표현한다.

쓰레드는 추가로 상대적 우선순위를 갖는다.

 Priority   의미 
 THREAD_PRIORITY_LOWEST  -2
 THREAD_PRIORITY_BELOW_NORMAL  -1
 THREAD_PRIORITY_NORMAL  0 (Default)
 THREAD_PRIORITY_ABOVE_NORMAL  +1
 THREAD_PRIORITY_HIGHEST  +2

예)

NORMAL_PRIORITY_CLASS (기존 우선순위 9) + THREAD_PRIORITY_LOWEST(-2) = 7

즉, 이 쓰레드의 최종우선순위는 7이다


쓰레드의 상대적 우선순위 변경 :

BOOL SetThreadPriority(
        HANDLE hThread,        // 우선순위를 변경할 쓰레드의 핸들
        int nPriority                  // 우선순위 상수값
);

int GetThreadPriority(
        HANDLE hThread         // 우선순위를 확인할 쓰레드의 핸들
);

'Windows > _System Programming' 카테고리의 다른 글

쓰레드(Thread) 실행순서 동기화  (0) 2010.03.04
쓰레드(Thread) 메모리 접근 동기화  (0) 2010.03.04
쓰레드(Thread)의 생성과 소멸  (0) 2010.02.28
쓰레드(Thread)  (2) 2010.02.28
환경변수  (0) 2010.02.25
스케줄링 알고리즘과 우선순위  (0) 2010.02.25
Posted by Dakuo

쓰레드(Thread) : 하나의 프로그램 내에서 여러 개의 실행 흐름을 두기 위한 모델


1. 독립적인 스택(Stack)을 가진다.

2. 코드 영역을 공유한다.

(위와 같이 쓰레드 main 함수는 코드 영역에 존재하는 모든 함수를 호출할 수 있다)

3. 데이터 영역과 힙을 공유한다.(전역변수와 동적 할당된 메모리 공간 공유 가능)

4. 프로세스 핸들 테이블 공유

프로세스 핸들 테이블에 대한 핸들 정보는

프로세스 내의 쓰레드 들에게 공유되어 각 쓰레드가 그 핸들에 대해 접근이 가능하다
(참고 : 같은 프로세스내의 쓰레드들은 스택 이외의 모든 것을 공유한다)



프로세스와 쓰레드

Windows 에서 프로세스는 단순히 쓰레드를 담는 상자다.

실제 프로그램 흐름을 형성하는 것은 쓰레드이다.


따라서 스케줄러(Windows)가 볼때 2개의 프로세스가 아닌
 
실행 흐름을 가지고 있는 쓰레드 단위로 판단을 한다. 5개의 쓰레드를 인식한 후 스케줄링 한다.

(참고 : 컨텍스트 스위칭 시간

프로세스 A 내의 쓰레드 끼리의 컨텍스트 스위칭은 공유 영역이 많아 시간이 적게 걸린다.

하지만 프로세스 A와 프로세스 B 내의 쓰레드 끼리의 컨텍스트 스위칭은 공유 부분이 없어(프로세스끼리는 독립)

시간이 더 오래 걸린다)



커널(Kernel) 영역과 유저(User) 영역 :


유저 영역 : 사용자가 구현한 프로그램 동작시 사용하게 되는 메모리 영역

커널 영역 : 운영체제 동작시 사용하게 되는 메모리 영역


커널 레벨 쓰레드 :

쓰레드를 생성 및 스케줄링하는 주체가 커널


장점 : 안전성과 다양한 기능

단점 : 유저 모드와 커널 모드로의 전환으로 인해 성능이 저하된다.

(참고 : 사용자가 구현한 프로그램은 기본적으로 유저모드에서 동작하다가 Windows 커널이 실행되어야 하는 경우
커널 모드로의 전환이 일어나고 일을 마치면 다시 유저 모드로 전환된다)


유저 레벨 쓰레드 :

커널에 의존적이지 않은 형태로 쓰레드의 기능을 제공하는 라이브러리를 활용

(참고 : 스케줄러는 쓰레드를 지원하지 않아 쓰레드의 존재를 모른다. 따라서 프로세스 단에서 스케줄링을 한다
따라서 쓰레드 끼리의 스케줄링은 유저가 구현해야 한다) 

장점 : 유저모드에서 커널모드로의 전환이 필요없다. 성능이 좋다

단점 : 프로그래밍 하기 어렵고 커널 레벨 쓰레드에 비해 결과 예측이 어렵다.

'Windows > _System Programming' 카테고리의 다른 글

쓰레드(Thread) 메모리 접근 동기화  (0) 2010.03.04
쓰레드(Thread)의 생성과 소멸  (0) 2010.02.28
쓰레드(Thread)  (2) 2010.02.28
환경변수  (0) 2010.02.25
스케줄링 알고리즘과 우선순위  (0) 2010.02.25
파이프(Pipe) IPC 통신 소스  (0) 2010.02.24
Posted by Dakuo