理解Linux的進程,線程,PID,LWP,TID,TGID

來源:互聯網
上載者:User

在Linux的top和ps命令中,預設看到最多的是pid (process ID),也許你也能看到lwp (thread ID)和tgid (thread group ID for the thread group leader)等等,而在Linux庫函數和系統調用裡也許你注意到了pthread id和tid等等。還有更多的ID,比如pgrp (process group ID), sid (session ID for the session leader)和 tpgid (tty process group ID for the process group leader)。概念太多可能很暈,但是只要對Linux的進程和線程的基本概念有準確的理解,這些ID的含義都迎刃而解。下面將介紹進程和線程的核心概念,並以一個樣本程式來驗證這些ID之間的關係。

 

Linux的進程和線程

Linux的進程和線程有很多異同點,可以Google下。但只要能清楚地理解一下幾點,則足夠理解Linux中各種ID的含義。

  • 進程是資源分派的基本單位,線程是調度的基本單位
  • 進程是資源的集合,這些資源套件括記憶體位址空間,檔案描述符等等,一個進程中的多個線程共用這些資源。
  • CPU對任務進行調度時,可調度的基本單位 (dispatchable entity)是線程。如果一個進程中沒有其他線程,可以理解成這個進程中只有一個主線程,這個主進程獨享進程中的所有資源。
  • 進程的個體間是完全獨立的,而線程間是彼此依存,並且共用資源。多進程環境中,任何一個進程的終止,不會影響到其他非子進程。而多線程環境中,父線程終止,全部子線程被迫終止(沒有了資源)。

上述第一點說明是最基礎的,也是最重要的。

 

初步理解各種ID。基本上按照重要程度從高到低,在分割線下方的IDs不太重要。

  • pid: 進程ID。
  • lwp: 線程ID。在使用者態的命令(比如ps)中常用的顯示方式。
  • tid: 線程ID,等於lwp。tid在系統提供的介面函數中更常用,比如syscall(SYS_gettid)和syscall(__NR_gettid)。
  • tgid: 線程組ID,也就是線程組leader的進程ID,等於pid。
  • ------分割線------
  • pgid: 進程組ID,也就是進程組leader的進程ID。
  • pthread id: pthread庫提供的ID,生效範圍不在系統層級,可以忽略。
  • sid: session ID for the session leader。
  • tpgid: tty process group ID for the process group leader。

 從上面的列表看出,各種ID最後都歸結到pid和lwp(tid)上。所以理解各種ID,最終歸結為理解pid和lwp(tid)的聯絡和區別。

 

下面的圖是一張描述父子進程,線程之間關係的圖。

很好地描述了使用者視角(user view)和核心視角(kernel view)看到線程的差別:

  • 從使用者視角出發,在pid 42中產生的tid 44線程,屬於tgid(線程組leader的進程ID) 42。甚至用ps和top的預設參數,你都無法看到tid 44線程。
  • 從核心視角出發,tid 42和tid 44是獨立的調度單元,可以把他們視為"pid 42"和"pid 44"。

需要指出的是,有時候在Linux中進程和線程的區分也是不是十分嚴格的。即使線程和進程混用,pid和tid混用,根據上下文,還是可以清楚地區分對方想要表達的意思。中,從核心視角出發看到了pid 44,是從調度單元的角度出發,但是在top或ps命令中,你是絕對找不到一個pid為44的進程的,只能看到一個lwp(tid)為44的線程。

 

理解pid和lwp(tid)的樣本程式

下面利用一個樣本程式來進一步理解pid和lwp(tid),以及利用格式化的ps命令列印出各種ID。下面的程式在main函數中建立了2個子線程,加上main函數這個主線程,一共有3個線程。在3個線程中分別列印pthread id, pid和lwp(tid),來驗證pid和lwp(tid)的關係。

 1 #include <unistd.h> 2 #include <sys/syscall.h> 3 #include <stdio.h> 4 #include <pthread.h> 5  6 #define gettidv1() syscall(__NR_gettid) // new form 7 #define gettidv2() syscall(SYS_gettid)  // traditional form 8  9 void *ThreadFunc1()10 {11         printf("the pthread_1 id is %ld\n", pthread_self());12         printf("the thread_1's Pid is %d\n", getpid());13         printf("The LWPID/tid of thread_1 is: %ld\n", (long int)gettidv1());14         pause();15 16         return 0;17 }18 19 void *ThreadFunc2()20 {21         printf("the pthread_2 id is %ld\n", pthread_self());22         printf("the thread_2's Pid is %d\n", getpid());23         printf("The LWPID/tid of thread_2 is: %ld\n", (long int)gettidv1());24         pause();25 26         return 0;27 }28 29 int main(int argc, char *argv[])30 {31         pid_t tid;32         pthread_t pthread_id;33 34         printf("the master thread's pthread id is %ld\n", pthread_self());35         printf("the master thread's Pid is %d\n", getpid());36         printf("The LWPID of master thread is: %ld\n", (long int)gettidv1());37 38         // 建立2個線程39         pthread_create(&pthread_id, NULL, ThreadFunc2, NULL);40         pthread_create(&pthread_id, NULL, ThreadFunc1, NULL);41         pause();42 43         return 0;44 }

注意編譯的時候要利用-l指定library參數。

# gcc threadTest.c -o threadTest -l pthread

 

執行程式,結果如下:

# ./threadTestthe master thread's pthread id is 140154481125184the master thread's Pid is 20992The LWPID of master thread is: 20992the pthread_1 id is 140154464352000the thread_1's Pid is 20992The LWPID/tid of thread_1 is: 20994the pthread_2 id is 140154472744704the thread_2's Pid is 20992The LWPID/tid of thread_2 is: 20993

上述結果說明pthread id是pthread庫提供的ID,在系統層級沒有意義。pid都是線程組leader的進程ID,即20992。而lwp(tid)則是線程ID,分別是20993和20994。

 

同時利用ps來查看結果,注意ps預設只列印進程層級資訊,需要用-L選項來查看線程基本資料。

# ps -eo pid,tid,lwp,tgid,pgrp,sid,tpgid,args -L | awk '{if(NR==1) print $0; if($8~/threadTest/) print $0}'  PID   TID   LWP  TGID  PGRP   SID TPGID COMMAND20992 20992 20992 20992 20992 30481 20992 ./threadTest20992 20993 20993 20992 20992 30481 20992 ./threadTest20992 20994 20994 20992 20992 30481 20992 ./threadTest

從上述結果中可以看到:

  • PID=TGID: 20992
  • TID=LWP: 20993 or 20994
  • 至於SID,30481是bash shell的進程ID。

 

Linux使用者態命令查看線程top

預設top顯示的是task數量,即進程。

可以利用敲"H",來切換成線程。如下,可以看到實際上有96個線程。也可以直接利用top -H命令來直接列印線程情況。

 

ps

ps的-L選項可以看到線程,通常能列印出LWP和NLWP相關資訊。如下命令即可查看線程資訊:

ps -eLf

 

pidstat

pidstat -t [-p pid號] 可以列印出線程之間的關係。

 

htop

要在htop中啟用線程查看,開啟htop,然後按<F2>來進入htop的設定菜單。選擇“設定”欄下面的“顯示選項”,然後開啟“樹狀檢視”和“顯示自訂線程名”選項。按<F10>退出設定。
註:MAC的F2按fn+F2。

 

參考

Linux進程與線程的區別

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.