Microsoft MVP성태의 닷넷 이야기
Linux: 108. Linux와 Windows의 프로세스/스레드 ID 관리 방식 [링크 복사], [링크+제목 복사],
조회: 5100
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 2개 있습니다.)
스크립트: 44. 파이썬의 3가지 스레드 ID
; https://www.sysnet.pe.kr/2/0/13251

Linux: 108. Linux와 Windows의 프로세스/스레드 ID 관리 방식
; https://www.sysnet.pe.kr/2/0/13821




Linux와 Windows의 프로세스/스레드 ID 관리 방식

윈도우 기반의 개발자가 Linux로 이전하면서 혼란을 느끼는 것 중의 하나가 바로 프로세스와 스레드일 것입니다. ^^;

우선, 윈도우는 프로세스와 스레드의 관계가 주종 관계입니다.

EPROCESS_1
   |- 스레드_1 (ETHREAD) 
   |- 스레드_2 (ETHREAD)
   :    ...   (ETHREAD)
   ㄴ 스레드_N (ETHREAD)

EPROCESS_2
   |- 스레드_1 (ETHREAD) 
   |- 스레드_2 (ETHREAD)
   :    ...   (ETHREAD)
   ㄴ 스레드_N (ETHREAD)

따라서, 프로세스의 ID는 EPROCESS 구조체에 담긴 ID 필드 값이고, 스레드의 ID는 ETHREAD 구조체에 담긴 ID 필드 값으로 분리돼 있습니다.

lkd> dt _EPROCESS
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x438 ProcessLock      : _EX_PUSH_LOCK
   +0x440 UniqueProcessId  : Ptr64 Void
   +0x448 ActiveProcessLinks : _LIST_ENTRY
   ...[생략]...
   +0x5e0 ThreadListHead   : _LIST_ENTRY
   ...[생략]...

lkd> dt _ETHREAD
nt!_ETHREAD
   +0x000 Tcb              : _KTHREAD
   +0x430 CreateTime       : _LARGE_INTEGER
   +0x438 ExitTime         : _LARGE_INTEGER
   ...[생략]...
   +0x478 Cid              : _CLIENT_ID
   ...[생략]...

lkd> dt _CLIENT_ID
nt!_CLIENT_ID
   +0x000 UniqueProcess    : Ptr64 Void
   +0x008 UniqueThread     : Ptr64 Void

하지만, 리눅스 세계에서는 프로세스와 스레드의 구분이 없고 모든 것이 "Task"입니다.

Task_1
   |- Task_2
   |- Task_3
   : ...
   ㄴ Task_N

Task_N+1
    |- Task_N+2
    |- Task_N+3
    : ...
    ㄴ Task_N+N

문제는, Task를 표현하는 task_struct 구조체 필드의 이름이 윈도우 세계의 개념과 혼동을 줄 수 있다는 점입니다.

$ grep -A 214 "struct task_struct {" vmlinux.h
struct task_struct {
        ...[생략]...
        pid_t pid;
        pid_t tgid;
        ...[생략]...
        struct key *cached_requested_key;
        char comm[16];
        ...[생략]...
};

// https://www.linkedin.com/pulse/brief-linux-process-amit-nadiger/

pid: the process ID of the process
tgid: the thread group ID of the process

pid를 "process ID"라고 설명하고 있는데요, 저 말을 윈도우 세계의 프로세스/스레드 개념으로 이해하면 안 됩니다. 즉, 리눅스에서 저 2개의 필드는 실은 다음과 같은 의미로 쓰입니다.

pid: task id (윈도우라면 스레드 ID와 유사)
tgid: task group id (윈도우라면 프로세스 ID와 유사)

실제로, 저 개념으로 보면 그나마 윈도우 운영체제의 프로세스/스레드 개념과 비슷하게 이해할 수 있습니다. 가령, task를 하나 생성하면 최초에 pid와 tgid는 동일한 값으로 나옵니다.

[신규 task 생성]
pid == 100
tgid == 100

그리고, 저 task에서 새로운 스레드(task)를 하나 생성하면 pid는 새로운 값으로 변경되지만, tgid는 부모 task의 tgid 값으로 결정됩니다.

[task에서 신규 스레드 생성]
pid == 100
tgid == 100
    pid == 101
    tgid == 100

반면, 스레드가 아닌 자식 프로세스의 개념(예를 들어, fork)으로 task를 생성하는 경우에는 pid는 언제나처럼 새로운 값으로 변경되고, tgid는 다시 그 pid의 값을 따르게 됩니다.

[task에서 신규 프로세스 생성]
pid == 100
tgid == 100
    pid == 101
    tgid == 101

그런데, 위의 필드들과 관련된 함수들을 보면 더욱더 혼란스러운 면이 있습니다.

pid_t getpid (void): task_struct의 tgid 반환 (윈도우라면 프로세스 ID와 유사)

pid_t getppid (void): task_struct의 real_parent의 tgid 반환 (윈도우라면 부모 프로세스 ID와 유사)

pid_t gettid (void): task_struct의 pid 반환 (윈도우라면 스레드 ID와 유사)

보는 바와 같이 getpid가 (pid가 아닌) tgid를 반환하고, gettid가 pid를 반환하는 식입니다. 즉, 함수 측면에서 보면 오히려 윈도우의 프로세스/스레드 개념과 유사하게 이해할 수 있습니다.




참고로, "pstree" 명령어를 사용하면 리눅스 시스템에서 프로세스/스레드의 관계를 트리 구조로 확인할 수 있습니다.

systemd─┬─ModemManager───2*[{ModemManager}]
        ├─NetworkManager───2*[{NetworkManager}]
        ├─accounts-daemon───2*[{accounts-daemon}]
...[생략]...

한 가지 유의해야 할 점은, 위에서 systemd와 ModemManager는 프로세스의 부모/자식 관계인 반면, ModemManager와 "2*[{ModemManager}]"는 같은 프로세스에서의 스레드 부모/자식 관계입니다. 이름으로 그렇게 구분하는 것은 아니고, "{", "}" 중괄호로 묶인 것이 스레드라는 의미이기 때문인데요, 스레드의 경우 앞서 표기된 "2"라는 숫자는 스레드의 개수를 의미합니다. (윈도우의 관점에서 해석하면, ModemManager 프로세스에는 Main 스레드 1개와 secondary 스레드 2개로 총 3개의 스레드가 존재하는 걸로 이해할 수 있습니다.)

마지막으로 리눅스와 윈도우 모두 스레드 ID는 시스템 내에서 유일한 값임을 보증할 수 있습니다. 단지, 리눅스의 경우에는 꾸준히 증가하는 식으로 할당이 되는 반면, 윈도우는 스레드가 종료되면 그 ID가 재사용될 수 있으므로 주의가 필요합니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 11/18/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 31  [32]  33  34  35  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
13137정성태10/8/202214157.NET Framework: 2055. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프로부터 닷넷 모듈을 추출하는 방법
13136정성태10/7/202214515.NET Framework: 2054. .NET Core/5+ SDK 설치 없이 dotnet-dump 사용하는 방법
13135정성태10/5/202215031.NET Framework: 2053. 리눅스 환경의 .NET Core 3/5+ 메모리 덤프를 분석하는 방법 - 두 번째 이야기 [1]
13134정성태10/4/202212239오류 유형: 820. There is a problem with AMD Radeon RX 5600 XT device. For more information, search for 'graphics device driver error code 31'
13133정성태10/4/202213374Windows: 211. Windows - (commit이 아닌) reserved 메모리 사용량 확인 방법 [1]
13132정성태10/3/202213399스크립트: 42. 파이썬 - latexify-py 패키지 소개 - 함수를 mathjax 식으로 표현
13131정성태10/3/202217201.NET Framework: 2052. C# - Windows Forms의 데이터 바인딩 지원(DataBinding, DataSource) [2]파일 다운로드1
13130정성태9/28/202213019.NET Framework: 2051. .NET Core/5+ - 에러 로깅을 위한 Middleware가 동작하지 않는 경우파일 다운로드1
13129정성태9/27/202213644.NET Framework: 2050. .NET Core를 IIS에서 호스팅하는 경우 .NET Framework CLR이 함께 로드되는 환경
13128정성태9/23/202216574C/C++: 158. Visual C++ - IDL 구문 중 "unsigned long"을 인식하지 못하는 #import [1]파일 다운로드1
13127정성태9/22/202214828Windows: 210. WSL에 systemd 도입
13126정성태9/15/202215358.NET Framework: 2049. C# 11 - 정적 메서드에 대한 delegate 처리 시 cache 적용
13125정성태9/14/202215767.NET Framework: 2048. C# 11 - 구조체 필드의 자동 초기화(auto-default structs)
13124정성태9/13/202215554.NET Framework: 2047. Golang, Python, C#에서의 CRC32 사용
13123정성태9/8/202215612.NET Framework: 2046. C# 11 - 멤버(속성/필드)에 지정할 수 있는 required 예약어 추가
13122정성태8/26/202216017.NET Framework: 2045. C# 11 - 메서드 매개 변수에 대한 nameof 지원
13121정성태8/23/202212430C/C++: 157. Golang - 구조체의 slice 필드를 Reflection을 이용해 변경하는 방법
13120정성태8/19/202216022Windows: 209. Windows NT Service에서 UI를 다루는 방법 [3]
13119정성태8/18/202215145.NET Framework: 2044. .NET Core/5+ 프로젝트에서 참조 DLL이 보관된 공통 디렉터리를 지정하는 방법
13118정성태8/18/202212683.NET Framework: 2043. WPF Color의 기본 색 영역은 (sRGB가 아닌) scRGB [2]
13117정성태8/17/202216371.NET Framework: 2042. C# 11 - 파일 범위 내에서 유효한 타입 정의 (File-local types)파일 다운로드1
13116정성태8/4/202216799.NET Framework: 2041. C# - Socket.Close 시 Socket.Receive 메서드에서 예외가 발생하는 문제파일 다운로드1
13115정성태8/3/202217367.NET Framework: 2040. C# - ValueTask와 Task의 성능 비교 [1]파일 다운로드1
13114정성태8/2/202217277.NET Framework: 2039. C# - Task와 비교해 본 ValueTask 사용법파일 다운로드1
13113정성태7/31/202216751.NET Framework: 2038. C# 11 - Span 타입에 대한 패턴 매칭 (Pattern matching on ReadOnlySpan<char>)
13112정성태7/30/202217613.NET Framework: 2037. C# 11 - 목록 패턴(List patterns) [1]파일 다운로드1
... 31  [32]  33  34  35  36  37  38  39  40  41  42  43  44  45  ...