일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Dijkstra
- 이진탐색
- union find
- Brute Force
- two pointer
- DP
- 다익스트라
- String
- Trie
- Hash
- 그래프
- Two Points
- binary search
- SQL
- 스토어드 프로시저
- Stored Procedure
- MYSQL
- Today
- Total
codingfarm
6. 커널 오브젝트와 오브젝트 핸들 본문
1. 커널 오브젝트에 대한 이해
∙ 커널 : 컴퓨터를 운영하는데 있어서 중심이되는 운영체제의 핵심 프로그램
∙ 커널을 운영체제와 똑같이 취급하는 서적도 있다.
커널오브젝트에 대한 이해
∙ 커널오브젝트 : 커널에서 관리하는 리소스의 정보를 관리하는 데이터 블록
∙ 커널오브젝트가 프로세스 관리(생성,소멸,변화,상태정보,우선순위 정보...)의 주체이다.
커널 오브젝트(Kernel Object)
∙ 프로세스의 정보, 상태 등을 저장하고 관리하기 위해 정의된 구조체
∙ 프로세스의 상태정보(running, blockd, ready...)와 우선순위정보는 OS내부에 저장되어야 하며 정보가 변경될때마다 갱신되어야 한다.
∙ 프로세스가 생성될때마다 이 구조체 변수가 하나씩 생성되며 프로세스의 정보들로 초기화 된다.
∙ 프로그래머가 직접 조작이 불가능하다(handle을 통해 간접적으로 접근 및 제어)
∙ 커널오브젝트는 프로세스 관리 구조체의 객체이다.

그 이외의 kernel objects
∙ 프로세스 뿐만 아니라 쓰레드 IPC를 위해 사용되는 mailslot이나 pipe를 생성할때도 kernel object를 만든다.
∙ 대상에 따라 kernel object의 형태와 구성멤버도 달라져야 한다.
∙ Windows에서 만드는 모든 Kernel object는 그 종류에 따라 서로 다른 구조체를 기반으로 생성된다.
∴ kernel object란 windows OS가 프로세스, 스레드, 파일과 같은 리소스를 원활히 관리하기 위해 필요한 정보를 저장할 메모리 블록을 지칭하는 말이다.

Windows kernel에 의해 관리되는 리소스의 수 = kernel ojbect의 수
object handle을 이용한 kernel object의 조작
\bullet kernel object는 직접적인 조작이 불가능하지만 함수 호출에 의한 간접적인 조작은 가능하다.
\bullet resource의 특성 변겨을 위해 시스템 함수를 사용한다.
프로세스의 우선순위(priority)변경 함수
1
2
3
4
|
BOOL SetPriorityClass(
HANDLE hProcess,
DWORD dwPriorityClass
);
|
cs |
1) HANDLE hProcess
\bullet A handle to the process
\bullet 우선순위를 변경할 프로세스의 핸들을 전달한다.
2) DWORD dwPriorityClass
\bullet The priority class for the process
\bullet 역할 : sets the priority class for the specified process. This value together with the priority value of each thread of the process determines each thread's base priority level.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
//Operator1.cpp
#include<stdio.h>
#include<tchar.h>
#include<windows.h>
int _tmain(int argc, TCHAR* argv[]) {
STARTUPINFO si = { 0, };
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
TCHAR command[] = _T("Operator2.exe");
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
CreateProcess(
NULL, command, NULL, NULL,
TRUE, 0, NULL, NULL, &si, &pi
);
while (1) {
for (DWORD i = 0; i < 10000; i++)
for (DWORD i = 0; i < 10000; i++);
_fputts(_T("Operator1.exe \n"), stdout);
}
return 0;
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//Operation2.cpp
#include<stdio.h>
#include<tchar.h>
#include<windows.h>
int _tmain(int argc, TCHAR* argv[]) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
while (1) {
for (DWORD i = 0; i < 10000; i++)
for (DWORD i = 0; i < 10000; i++);
_fputts(_T("Operator2.exe \n"), stdout);
}
return 0;
}
|
cs |

똑같이 10000번 문자열을 출력하는 프로그램이지만 우선순위가 더 높은 operator2.exe가 미세하게 더 많이 출력하는것을 볼 수 있다.
우선순위는 사실상 프로세스가 CPU에 할당되는 시간 비율을 나타내는 척도라 볼 수 있다.
즉, 높은 우선순위의 프로세스의 함수가 호출되어 실행되는 중간에도 낮은 프로세스가 CPU의 할당시간을 받을 수 있다.
핸들(Handle)
\bullet 커널 오브젝트에 할당 되는 숫자.(실제로는 숫자가 아님)
\bullet 프로그래머가 kernel object에 간접적으로 접근할 때 사용한다.
\bullet kernel object를 생성할때마다 handle을 부여한다.

handle 정보는 어디서?
\bullet handle의 정보를 얻는법은 kernel object의 종류에 따라 다르며, 함수가 제공된다.
2. 커널 오브젝트와 핸들의 종속 관계
커널 오브젝트와 핸들 사이의 종속 관계에 대해 알아보겠다.
커널 오브젝트의 종속 관계
커널오브젝트는 프로세스가 아는 운영체제에 종속적인 관계이다.
- 커널오브젝트의 소멸시점은 운영체제에 의해 결정된다.
- 커널오브젝트의 여러 프로세스에 의해서 접근이 가능하다.
-하나의 커널 오브젝트에 둘 이상의 프로세스가 함수호출을 통해 간접적으로 접근이 가능하다.
핸들의 종속관계(추후 배울것)
-핸들은 프로세스에 종속적이다.
--프로세스는 각자 자신만의 핸들테이블을 지니며 핸들 값과 대응되는 커널오브젝트에 접근 가능하다.
커널 오브젝트의 공유
-앞서 하나의 커널오브젝트에 둘 이상의 프로세스가 접근 가능함을 말하였다.
-프로세스가 핸들과 핸들테이블 정보를 지녔다면 커널 오브젝트에 접근 가능하다.
가령 자식프로세스와 부모프로세스가 자식프로세스의 커널 오브젝트의 우선순위를 조작하는 방법은 아래와 같다.

부모 프로세스에서 자식 프로세스의 핸들에 접근하여 우선순위를 조절하는 예제 코드를 확인해보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#include<stdio.h>
#include<tchar.h>
#include<windows.h>
int _tmain(int argc, TCHAR* argv[]) {
STARTUPINFO si = { 0, };
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
TCHAR command[] = _T("Operation2.exe");
CreateProcess(
NULL, command, NULL, NULL, TRUE,
0,NULL,NULL,&si, &pi
);
DWORD timing = 0;
while (1) {
for (DWORD i = 0; i < 10000; i++)
for (DWORD i = 0; i < 10000; i++);
_fputts(_T("Parent \n"), stdout);
timing += 1;
if (timing == 2)
SetPriorityClass(pi.hProcess, NORMAL_PRIORITY_CLASS);
}
return 0;
}
|
cs |
PROCESS_INFORMATION 구조체
CreateProcess의 10번째 매개변수로 들어가는 자료형이며 만들어 지게 되는 process에 대한 여러 정보들이 담기게 된다.
1
2
3
4
5
6
|
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
|
cs |
1) process handle
-process의 kernel object를 가리키기(구분짓기) 위한것
2) process id
-process 자체를 구분짓기 위한것
3,4) thread
-운영체제가 process 생성시, process 내부적으로 생성하는 가벼운(light weight) process
-이를 통해 main 함수가 호출된다.
3. kernel object와 usage count
\bullet kernel object는 운영체제에 종속적이므로 소멸시기는 운영체제에 의해서 결정된다.
\bullet kernel object의 생성 주체 또한 운영체제이다.
1) CloseHandle 함수에 대한 이해
\bullet 프로세스가 생성되면 프로세스를 위한 커널 오브젝트도 생성된다.
\bullet kernel object는 완전히 프로세스를 대표한다
-역은 성립하지 않는다. 프로세스가 소멸된다해서 kernel object가 소멸되는것은 아니다(소멸 될수도 안될수도 있다.)
1
|
BOOL CloseHandle(HANDLE hObject);
|
cs |
https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
closehandle을 호출한다해서 프로세스가 종료되는것은 아니며 kernel object도 당장 소멸되지 않는다.
아래의 코드와 함께 확인해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include<stdio.h>
#include<tchar.h>
#include<windows.h>
int main(int argc, TCHAR* argv[]) {
STARTUPINFO si = { 0, };
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
TCHAR command[] = _T("Project2.exe");
CreateProcess(
NULL, command, NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi
);
CloseHandle(pi.hProcess);
return 0;
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include<stdio.h>
#include<tchar.h>
#include<windows.h>
int _tmain(int argc, TCHAR* argv[]) {
DWORD n = 0;
while (n < 100) {
for (DWORD i = 0; i < 10000; i++)
for (DWORD i = 0; i < 10000; i++);
_fputts(_T("proejct2.exe \n"), stdout);
n++;
}
return 0;
}
|
cs |
생성된 프로세스의 핸들을 곧바로 닫는 코드이다.
"project2.exe"가 호출되기 전에 CloseHandle함수에 의해 닫히는 모습을 볼 수 있다.
그렇다면 실제 출력은 어떠한가?

CloseHandle을 호출하고 부모 프로세스가 종료되었음을 확인할 수 있지만 자식 프로세스는 여전히 살아남아 문자열을 출력함을 확인 할 수 있다.
이를통해 CloseHandle 함수 호출에 의해서 B 프로세스가 소멸되지 않았음을 확인할 수 있다.
꼭 CloseHandle에 의한것이 아닐지라도 OS는 프로세스의 종료와 동시에 kernel object를 소멸시키지 않는다.
2) CloseHandle 함수와 프로세스 종료코드
왜 운영체제는 프로세스의 종료와 동시에 kernel object를 소멸시키지 않을까?
만약 프로세스의 종료와 동시에 kernel object도 소멸된다면 프로세스의 종료코드를 얻을 수 없기 때문이다.
\bullet 운영체제가 커널 오브젝트 소멸 시점을 결정 짓는 방법
1) 프로세스가 종료되어야 한다.
2) 커널오브젝트를 창조하는 대상이 하나도 없을 때 소멸 시키는 것이 가장 이상적이다
(usage count가 0이 되는 순간)
종료된 프로세스로부터 종료 코드를 얻기 위해선 GetExitCodeProcess 함수를 사용한다.
1
|
BOOL GetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode);
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include<stdio.h>
#include<tchar.h>
#include<windows.h>
int main(int argc, TCHAR* argv[]) {
STARTUPINFO si = { 0, };
PROCESS_INFORMATION pi;
DWORD state;
si.cb = sizeof(si);
si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE;
si.dwX = 100;
si.dwY = 200;
si.dwXSize = 300;
si.dwYSize = 200;
TCHAR tmp[] = _T("return & exit");
si.lpTitle = tmp;
TCHAR command[] = _T("OperationStateChild.exe");
CreateProcess(NULL, command,
NULL, NULL, TRUE,
CREATE_NEW_CONSOLE,
NULL, NULL,
&si, &pi);
for (DWORD i = 0; i < 10000; i++)
for (DWORD i = 0; i < 100000; i++);
// WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &state);
if (state == STILL_ACTIVE)
_tprintf(_T("STILL_ACTIVE \n\n"));
else
_tprintf(_T("state : %d \n\n"), state);
//CloseHandle(pi.hProcess);
return 0;
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include<stdio.h>
#include<stdlib.h>
#include<tchar.h>
#include<windows.h>
int _tmain(int argc, TCHAR* argv[]) {
float num1, num2;
_fputts(_T("Return Value Test \n"), stdout);
_tscanf(_T("%f %f"), &num1, &num2);
if (num2 == 0)
exit(-1); //or return -1;
_tprintf(_T("Operation Result : %f \n"), num1 / num2);
return 1;
}
|
cs |
3) kernel object와 usage count
\bullet 프로세스의 종료코드는 kernel object에 저장된다.
\bullet 이상적인 kernel object의 소멸 타이밍 = kernel object를 참조하는 대상이 하나도 없을때
-usage count가 0이 되는 순간

Usage Count
\bullet 프로세스는 생성과 동시에 kernel object의 usage cont가 2가 된다.(부모, 자식 프로세스)
- process와 thread는 생성과 동시에 usage count가 2이다.
- 나머지 resource의 usage count는 1이다.
\bullet kerbel object에 접근가능한 대상이 늘어날때마다 usage count는 1씩 증가한다.
\bullet usage count는 kernel object의 멤버이다
\bullet close handle 함수는 핸들을 반환하면서 usage count를 1 감소시킨다.
\bullet process와 thread는 종료시점에서도 usage count를 1 감소시킨다.
4) CreateProcess 호출시 주의사항
\bullet 자식 프로세스는 소멸시키면 usage count가 줄어들지만 부모 프로세스는 계속 켜놓으면서 핸들 반환을 안하는경우, 이경우 계속해서 생성 \rightarrow소멸을 반복하면 kernel object는 쌓이게 된다.

결론
\bullet 바탕화면에서 프로세스를 실행시키든, 탐색기를 띄워서 실행시키든, 명령프롬프트 상에서 실행시키든 이 모든 경우가 부모 프로세스를 기반으로 자식프로세스를 생성하는 것이 되어 프로세스는 생성과 동시에 UC는 2가 된다.
\bullet 바탕화면 프로세스는 kernel object가 축적되는 결과를 야기하지 않도록 자식 프로세스 생성과정에서 얻은 핸들을 즉시 반환하여 UC가 1이된다.
복습
- 커널 오브젝트와 핸들
- 커널 오브젝트와 핸들이 무엇인가
- 이들은 무슨 관계인가
- 운영체제에 종속적인 커널 오브젝트
- 커널 오브젝트가 Windows 에 종속적이라는게 무슨의미인가?
- OS에 종속적이기 때문에 갖는 특성이 무엇인가?
- Usage Count
- Usage Count가 무엇인가?
- 이값은 어디에 존재하는가?
- 이 값이 증가하고 감소하는 시점은 언제인가?
- CloseHandle
- CloseHandle 함수의 기능이 무엇인가?
- 이 함수와 Usage Count와의 관계는 어떻게 되는가?
- 프로세스의 Usage Count
- 프로세스는 생성과 동시에 Usage Count는 1이 되지 않는다. 그 이유는 무엇인가?
- 종료 코드
- 종료코드란 무엇인가?
- 부모 프로세스가 자식 프로세스 핸들을 곧바로 반환하는 이유
- 부모 프로세스는 자식 프로세스 생성과정에서 얻게되는 자식 프로세스 핸들을 곧바로 반환한다. 그 이유가 무엇인가?
- 자식 프로세스의 핸들 반환 시간을 늦춰야 하는 경우에 대해 서술하라
'Windows > 윈도우즈 시스템 프로그래밍' 카테고리의 다른 글
18. 파일 I/O와 디렉터리 컨트롤 - 작성중 (0) | 2021.05.15 |
---|---|
7. 프로세스간 통신(IPC) 1 (0) | 2021.05.14 |
5. 프로세스의 생성과 소멸 (0) | 2020.06.15 |
4. 컴퓨터 구조에 대한 두 번째 이야기 (0) | 2020.05.29 |
2. 아스키코드와 유니코드 (0) | 2020.05.29 |