在多線程程序中,一個新的線程通常由一個進程調用phtread_create()函數而誕生的。新線程創建後,通常將這個進程稱爲主線程。你也許會有所迷惑:一個進程怎麼會編程線程?此刻有幾個線程,幾個進程?
其實通過上文對線程、輕量級進程以及線程組之間關係的理解後,這個問題似乎也不難回答。我們可以將所有的進程都看作一個線程組,只不過普通進程的線程組只包含它自己一個線程,它不能與其他線程共享資源,只能獨享自己的資源(而成爲進程)。
對於多線程程序來說,一旦在進程內創建了一個線程,那麼該進程也就搖身變成了一個線程。主線程和子線程共享“以前”那個進程所獨享的資源。主線程和子線程之間是並列關係,不存在類似fork()函數那樣的父子進程關係,這也就是不將創建線程的進程稱爲父線程的原因。
如果你還對上述的描述有所疑惑,那麼通過下面的實驗結果可以理解的更加深刻。下述的程序就是一個普通的線程創建,只不過主線程和子線程增加了延時以方便我們查看實驗結果。
01 |
int
* thread ( void * arg)
|
04 |
newthid = pthread_self(); |
05 |
printf ( "this a new thread and thread ID is=%lu\n" , newthid);
|
14 |
printf ( "main thread,ID is %lu\n" , pthread_self()); |
15 |
if
(pthread_create(&thid, NULL, ( void
*) thread , NULL) != 0) {
|
16 |
printf ( "thread creation failed\n" );
|
20 |
printf ( "my Id is %lu, new thread ID is %lu\n" , pthread_self(), thid);
|
我們帶開一個終端(稱爲終端1)運行上述程序,再另一個終端(稱爲終端2)裏使用ps -eLf命令查看系統當前的線程信息。
1 |
UID PID PPID LWP C NLWP STIME TTY TIME CMD
|
2 |
edsionte 2210 2208 2210 0 1 09:10 pts/0 00:00:00 bash
|
3 |
edsionte 2429 2210 2429 0 2 09:52 pts/0 00:00:00 ./createthread
|
4 |
edsionte 2429 2210 2430 0 2 09:52 pts/0 00:00:00 ./createthread
|
5 |
edsionte 2431 2208 2431 5 1 09:52 pts/1 00:00:00 bash
|
6 |
edsionte 2449 2431 2449 0 1 09:52 pts/1 00:00:00 ps -eLf |
請注意上述信息中三類ID信息:PID,PPID和LWP。LWP是輕量級進程的pid,NLWP爲線程組中線程的個數。下面對上述的實驗結果作以解釋。
1.運行實驗程序的終端對應的pid爲2210;
2.我們的實驗程序產生了兩個線程,其pid都是2429。這說明這兩個線程是並列關係,它們屬於同一個線程組,該線程組的pid爲2429。
3.實驗程序產生的兩個線程的PPID均爲2210,再次說明這兩個線程之間沒有父子關係,他們的父親均爲終端1對應的進程。
4.每個線程都與一個輕量級進程關聯,因此兩個線程的LWP不同,分別爲2429和2430。
5.這兩個線程形成一個線程組,因此他們對應的NLWP爲2。
6.通過pid,ppid和LWP的分配情況可以看到,內核對於進程和輕量級進程的id分配是統一管理的,這源於他們使用相同的數據結構task_struct。
上述分析基本上用實驗結果詮釋了進程、線程和輕量級進程之間的關係。