⑴ 如何去理解linux中進程,線程等概念
對於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 C++ Socket實現並發TCP伺服器(fork)
本文闡述了使用 Linux 下的 fork 函數實現並發 TCP 伺服器的過程。在編寫並發 TCP 客戶/伺服器程序時,需要處理多客戶端連接,實現並發處理,以提高伺服器的響應效率。具體步驟如下:
1. 首先,客戶機從標准輸入讀入一行文本,並將其發送給伺服器。
2. 伺服器則從網路輸入讀取這行文本,然後將文本回傳給客戶機。
3. 客戶機再從網路輸入讀取這行回傳的文本,並將其顯示在標准輸出上。
並發伺服器與迭代伺服器區別在於,迭代伺服器每次只處理一個客戶端連接,而並發伺服器則允許同時處理多個客戶端請求,使得服務效率提升。
並發伺服器實現方式主要有三種:進程、線程和 IO 復用。本文通過 fork 函數實現並發處理,當一個客戶端連接被處理後,伺服器會繼續處理下一個連接。
當客戶機調用 socket 和 connect 函數時,TCP 的三路握手完成,連接建立。隨後,客戶機調用 send 函數發送文本,伺服器則調用 accept 函數接受連接,並通過 fork 函數創建子進程。子進程調用 write 函數將輸入信息回傳給客戶機,同時,伺服器父進程繼續調用 accept 函數等待下一個客戶連接。
因此,系統中存在多個睡眠中的進程,包括客戶進程、伺服器父進程和伺服器子進程。當客戶機輸入文本後,文本會通過網路回傳至客戶機的輸出。
POSIX 信號處理機制允許進程在接收到特定事件時執行預定義的處理函數。信號可以由進程間傳遞,也可由內核觸發。本文重點介紹了如何使用 signal 函數和 sigaction 函數來處理信號,包括捕獲、忽略或使用默認處理方式。
以 SIGCHLD 信號為例,當子進程終止或停止時,父進程會接收到此信號。默認情況下,信號會被忽略。為了防止僵屍進程的產生,需要通過信號處理函數調用 wait 函數,以等待子進程結束。本文展示了如何定義和使用 sig__chld 函數來捕獲並處理 SIGCHLD 信號,確保子進程能夠被父進程正確等待。
最後,文章提及了 wait 和 waitpid 函數的原理和用法。其中,wait 函數阻塞當前進程直到等待到一個子進程終止,而 waitpid 函數則提供了更多控制,如指定等待的子進程 ID 和是否阻塞。
本文詳細介紹了使用 fork 函數實現並發 TCP 伺服器的過程,包括客戶端與伺服器的交互、並發處理方式、信號處理機制以及進程等待的實現。通過這些技術,可以構建高效、響應迅速的伺服器系統。
⑶ Linux中fork,vfork和clone詳解(區別與聯系)
在Linux系統中,進程復制的實現不僅僅是通過fork系統調用,而是包含了fork、vfork和clone三個功能各異的實現方式。下面將分別解析這三個系統調用及其特點、區別與聯系。
fork:這是Unix標準的進程復制機制,其本質是創建一個與當前進程完全相同的新進程。在fork後,父子進程的PID不同,且堆棧和數據資源完全復制。子進程對共享變數(如count)的修改不會影響到父進程的同名變數。
在復制過程中,Linux採用了寫時復制策略。子進程復制了父進程的task_struct、系統堆棧空間和頁面表,使得子進程與父進程在復制前共享相同的內存地址。然而,當子進程試圖對共享資源進行寫操作時,系統會通過_on_write機制為所涉及的頁面建立新的副本,從而防止直接修改共享資源。
第一代Unix系統採用了一種「傻瓜式」的進程創建方法,即fork時復制父進程的整個地址空間。這種方式耗時且不高效。現代Linux內核採用寫時復制(Copy On Write,COW),通過共享頁幀而不是復制頁幀來提高效率。當需要寫入共享頁幀時,系統會復制一份副本給進程。
vfork:vfork是fork的一個變種,它更偏向於創建輕量級的線程。vfork創建的子進程會立即執行exec或_exit函數,因此它在創建新進程後不會立即與父進程分離。這意味著子進程共享了父進程的虛擬地址空間。子進程對父進程的共享變數進行修改時,修改會直接影響到父進程的同名變數,因為它們共享同一塊內存。然而,如果在vfork後使用return退出子進程,會導致父進程再次調用vfork,進入循環,這是需要避免的情況。解決方法是使用exit或_exit代替return。
clone:clone函數是功能最強大的,提供了高度的靈活性,允許用戶選擇性地繼承父進程的資源。clone可以創建線程,共享父進程的虛存空間,或者創建獨立的進程。通過設置不同的標志參數(flags),用戶可以控制子進程是否與父進程共享資源、棧空間以及是否繼承某些進程特性。
盡管fork、vfork和clone都能實現進程復制,但它們的使用場景和行為有所差異。fork創建完全獨立的進程,vfork創建共享資源的輕量級線程,而clone提供了高度定製化的控制,允許更精細地管理子進程與父進程之間的資源共享。clone函數的參數豐富,靈活性高,可以創建線程或獨立進程,繼承或不繼承父進程的某些特性。
這三者之間的區別主要體現在資源復制、共享方式以及創建過程的效率上。在具體的應用場景中,選擇合適的系統調用可以優化程序的性能和資源管理。同時,理解它們之間的聯系有助於在不同需求下靈活運用進程復制機制。
總之,fork、vfork和clone分別適用於不同場景下的進程復制需求,理解它們的原理和用法對於提高程序的效率和實現更精細的資源管理具有重要意義。