windows下和linux下的進程和線程(轉)

對於windows來說,進程和線程的概念都是有着明確定義的,進程的概念對應於一個程序的運行實例(instance),而線程則是程序代碼執行的最小單元。也就是說windows對於進程和線程的定義是與經典OS課程中所教授的進程、線程概念相一致的。

提供API,CreateThread()用於建立一個新的線程,傳遞線程函數的入口地址和調用參數給新建的線程,然後新線程就開始執行了。

windows下,一個典型的線程擁有自己的堆棧、寄存器(包括程序計數器PC,用於指向下一條應該執行的指令在內存中的位置),而代碼段、數據段、打開文件這些進程級資源是同一進程內多個線程所共享的。因此同一進程的不同線程可以很方便的通過全局變量(數據段)進行通信,大家都可以對數據段進行讀寫,這很方便,也被在安全性方面詬病,因爲它要求程序員時刻意識到這些數據不是線程獨立的。

對於linux來說,則沒有很明確的進程、線程概念。首先linux只有進程而沒有線程,然而它的進程又可以表現得像windows下的線程。linux利用fork()和exec函數族來操作多線程。fork()函數可以在進程執行的任何階段被調用,一旦調用,當前進程就被分叉成兩個進程——父進程和子進程,兩者擁有相同的代碼段和暫時相同的數據段(雖然暫時相同,但從分叉開的時刻就是邏輯上的兩個數據段了,之所以說是邏輯上的,是因爲這裏是“寫時複製”機制,也就是,除非萬不得已有一個進程對數據段進行了寫操作,否則系統不去複製數據段,這樣達到了負擔最小),兩者的區別在於fork()函數返回值,對於子進程來說返回爲0,對於父進程來說返回的是子進程id,因此可以通過if(fork()==0)…else…來讓父子進程執行不同的代碼段,從而實現“分叉”。

exec函數族的函數的作用則是啓動另一個程序的新進程,然後完全用那個進程來代替自己(代碼段被替換,數據段和堆棧被廢棄,只保留原有進程id)。這樣,如果在fork()之後,在子進程代碼段裏用exec啓動另一個進程,就相當於windows下的CreateThread()的用處了,所以說linux下的進程可以表現得像windows下的線程。

然而linux下的進程不能像windows下線程那樣方便地通信,因爲他們沒有共享數據段、地址空間等。它們之間的通信是通過所謂IPC(InterProcess Communication)來進行的。具體有管道(無名管道用於父子進程間通信,命名管道可以用於任意兩個進程間的通信)、共享內存(一個進程向系統申請一塊可以被共享的內存,其它進程通過標識符取得這塊內存,並將其連接到自己的地址空間中,效果上類似於windows下的多線程間的共享數據段),信號量,套接字。

=================================分割線==================================

順便談一下自己對於linux文化的一點小感受。據我不多的瞭解來說,感覺linux在很多實現的風格上過於trick,它確實總讓我們有“原來還可以這樣!”、“真的很巧妙啊!”的驚歎,但是其實相同的問題還可以有更加一般化、更加經典、也更加容易理解的解決方案。fork()和CreateThread()的區別就很好地體現了這點。也許是因爲linux總是把效率放在第一位吧。我猜,正是因爲如此,正是因爲linux下的這種富tricks的風格,才讓linux粉們那麼容易產生優越感吧,不過這一點卻不怎麼吸引我,因爲我覺得這些實現方法上的小trick小差異並不是我們面對的問題的實質。

發佈了41 篇原創文章 · 獲贊 4 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章