做者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!html
http://www.cnblogs.com/vamei/archive/2012/09/20/2694466.htmllinux
http://www.cnblogs.com/vamei/archive/2012/10/09/2715393.htmlbash
指令:計算機能作的事情其實很是簡單,好比計算兩個數之和、尋找到內存中的某個地址。這些最基礎的計算機動做稱爲指令。session
程序:一系列指令所構成的集合。經過程序,咱們可讓計算機完成複雜的動做。程序大部分時候被存儲爲可執行文件。多線程
進程:進程是程序的一個具體實現,是正在執行的程序。併發
計算機開機時,內核只建立了一個init進程。剩下的全部進程都是init進程經過fork機制(新進程經過老進程複製自身獲得)創建的。函數
進程存活於內存中,每一個進程在內存中都有本身的一片空間spa
fork是一個系統調用。命令行
當進程fork時,linux在內存中開闢出新的一片內存空間給新的進程,並將老的進程空間的內容複製到新的進程空間中,此後兩個進程同時運行。線程
fork一般做爲一個函數被調用。這個函數會有兩次返回,將子進程的PID返回給父進程,0返回給子進程。
一般在調用fork函數以後,程序會設計一個if選擇結構。當PID等於0時,說明該進程爲子進程,那麼讓它執行某些指令,好比說使用exec庫函數(library function)讀取另外一個程序文件,並在當前的進程空間執行 (這其實是咱們使用fork的一大目的:爲某一程序建立進程);而當PID爲一個正整數時,說明爲父進程,則執行另一些指令。由此,就能夠在子進程創建以後,讓它執行與父進程不一樣的功能。
以幀(stack frame)爲單位。
幀中存儲當前激活函數的參數和局部變量,以及該函數的返回地址。
當程序調用函數時,stack向下增加一幀。
當激活函數返回時,會從棧中彈出(pop,讀取並從棧中刪除)該幀,並根據幀中記錄的返回地址,經控制權交給返回地址所指向的指令
從低到高存放常量、已初始化的全局/靜態變量、未初始化的全局/靜態變量
存放指令(也就是代碼段)
1.最下方的幀和Global Data一塊兒,構成了當前的環境。當前激活的函數能夠從環境中調取須要的變量
2.Text和Global data在進程一開始的時候就肯定了,並在整個進程中保持固定大小。
除了進程自身內存中的內容,每一個進程還要包括一些附加信息,包括PID、PPID、PGID等,用來講明進程身份、進程關係以及其餘統計信息。
這些信息保存在內核的內存空間中,內核爲每一個進程在內核的內存空間中保存一個變量(task_struct結構體)以保存上述信息。
內核能夠經過查看本身空間中各個進程的附加信息就能知道進程的狀況,而不用進入到進程自身的空間。
每一個進程的附加信息中有位置專門用於保存接收到的信號。
進程運行的過程當中,經過調用和返回函數,控制權不斷在函數間轉移。
進程在調用函數的時候,原函數的幀保留有離開原函數時的狀態,併爲新的函數開闢所需的幀空間。
在調用函數返回時,該函數的幀所佔據的空間隨着幀pop而清空。進程再次回到原函數的幀中所保留的狀態,並根據返回地址所指向的指令繼續執行。
上面的過程不斷繼續,棧不斷增加或減少直到main()函數返回,棧徹底清空,進程結束。
當程序使用malloc時,堆會向上增加,增加的部分就是malloc從內存中申請的空間。
malloc申請的空間會一直存在,直到使用free系統調用來釋放,或者進程結束。
內存泄漏 - 沒有釋放再也不使用的堆空間,致使堆不斷增大,可用內存不斷減小。
棧和堆的大小會隨着進程的運行增大或者變小,當棧頂和堆相遇時,該進程再無可用內存。則進程棧溢出,進程停止。
若是清理及時,依然棧溢出,則須要增長物理內存。
每一個進程屬於一個進程組,每一個進程組能夠包含多個進程。
進程組會有一個進程組領導進程(process group id),領導進程的PID成爲進程組的ID,即PGID。
領導進程能夠先終結,此時進程組依然存在,並持有相同的PGID,知道進程組中最後一個進程終結
進程組的重要做用是能夠發信號給進程組。進程組的全部進程都會收到該信號
多個進程組構成一個會話。
會話是由其中的進程創建的,該進程叫作會話的領導進程(session leader),領導進程的PID成爲識別會話的SID(session id)
會話中的每個進程組稱爲一個工做(job)。
會話能夠有一個進程組成爲會話的前臺工做,其餘進程組是後臺工做。
每一個會話能夠鏈接一個控制終端。
當控制終端有輸入輸出時,或者由終端產生的信號(ctrl+z/ctrl+c),都會傳遞給會話的前臺工做。
一個命令能夠末尾加上&讓它後臺運行。
能夠經過fg從後臺拿出工做,使其變爲前臺工做
bash支持工做控制,sh不支持。
獨佔stdin、(獨佔命令行窗口,只有運行完了或者手動終止,才能執行其餘命令)
能夠stdout、stderr
不繼承stdin(沒法輸入,若是須要讀取輸入,會halt暫停)
繼承stdout、stderr(後臺任務的輸出會同步在命令行下顯示)
用戶退出session時,系統向該session發送SIGHUP信號
session將SIGHUP信號發送給全部子進程
子進程收到SIGHUP信號後,自動退出
前臺工做確定會收到SIGHUP信號
後臺工做是否會收到SIGHUP信號,決定於huponexit參數($shopt | grep hupon),這個參數決定session退出時SIGHUP信號是否會發送給後臺工做
disown能夠將工做移出後臺工做列表,從而即便huponexit參數打開,在session結束時,系統也不會向不在後臺任務列表中的任務發送SIGHUP信號
標準I/O繼承於session,若是session結束,被移出的後臺任務有須要使用I/O,就會報錯終止執行
所以須要將目標任務的標準I/O進行重定向。
no hang up - 不掛起
nohup的進程再也不接受SIGHUP信號
nohup的進程關閉了stdin,即便在前臺。
nohup的進程將stdout、stderr重定向到nohup.out
做用:終端複用器,能夠在同一個終端裏面,管理多個session
不作深刻。
程序運行過程當中只有一個控制權存在,稱爲單線程
程序運行過程當中有多個控制權存在,稱爲多線程
單CPU的計算機,能夠經過不停在不一樣線程的指令間切換,形成相似多線程的效果
因爲一個棧只有棧頂幀可被讀寫,相應的,只有棧頂幀對應的函數處於運行中(激活狀態)
多進程的程序經過在一個進程內存空間中建立多個棧(每一個棧之間以必定空白區域隔開,以備棧的增加),從而繞開棧的限制
多個棧共享進程內存中的text、heap、global data區域。
因爲同一個進程空間存在多個棧,任何一個空白區域被填滿,都會致使stack overflow的問題
多線程至關於一個併發系統,併發系統通常同時執行多個任務
若是多個任務對共享資源同時有操做,則會致使併發問題
併發問題解決是將原先的兩個指令構成一個不可分隔的原子操做
同步是指必定的時間內只容許某一個線程訪問某個資源。
能夠經過互斥鎖、條件變量和讀寫鎖來實現同步資源
互斥鎖(mutex):把某一段程序代碼加鎖,即表示某一時間段內只容許一個線程去訪問這一段代碼,其餘的線程只能等待該線程釋放互斥鎖,才能夠訪問該代碼段
條件變量:通常與互斥鎖相結合,適用於多個線程等待某個條件的發生,而在條件發生時,這些等待的線程會同時被通知該條件已經發生,同時進行下一步工做。解決每一個線程須要不斷嘗試得到互斥鎖並檢查條件是否發生時出現的資源浪費狀況。
讀寫鎖:
一個unlock的RW lock能夠被某個線程獲取R鎖或者W鎖;
若是被一個線程得到R鎖,RW lock能夠被其它線程繼續得到R鎖,而沒必要等待該線程釋放R鎖。可是,若是此時有其它線程想要得到W鎖,它必須等到全部持有共享讀取鎖的線程釋放掉各自的R鎖。
若是一個鎖被一個線程得到W鎖,那麼其它線程,不管是想要獲取R鎖仍是W鎖,都必須等待該線程釋放W鎖。
IPC( interprocess communication )
方式:文本、信號、管道、傳統IPC
一個進程將信息寫入到文本中,另外一個進程去讀取
因爲是位於磁盤,因此效率很是低
能夠以整數的形式傳遞很是少的信息
能夠在兩個進程之間創建通訊渠道,分爲匿名管道PIPE和命名管道FIFO
主要指消息隊列(message queue)、信號量(semaphore)、共享內存(shared memory)。
這些IPC的特色是容許多個進程之間共享資源。可是因爲多進程任務具備併發性,因此也須要解決同步的問題。
與PIPE類似,也是創建一個隊列,先放入隊列的消息最早被取出。
不一樣點
消息隊列容許多個進程放入/取出消息。
每一個消息能夠攜帶一個整數識別符(message_type),能夠經過識別符對消息分類
進程從消息隊列中取出消息時,按照先進先出的順序取出,也能夠只取出某種類型的消息(也是先進先出的順序)。
消息隊列不使用文件API(即調用文件+參數)
消息隊列不會自動消失,他會一直存在於內核中,直到某個進程刪除該隊列
與mutex相似,是一個進程/線程計數鎖,容許被N個進程/線程取到,有更多的進程/線程申請時,會等待
一個semaphore會一直在內核中,直到某個進程/線程刪除它
一個進程能夠將本身內存空間中的一部分拿出來,容許其餘進程讀寫。
在使用共享內存的時候,一樣要注意同步的問題。
咱們可使用semaphore同步,也能夠在共享內存中創建mutex或者其餘的線程同步變量來同步
當子進程終結時候,它會通知父進程,並清空本身所佔據的內存,並在內核中留下本身的退出信息(exit code,0 - 正常退出,>0 - 異常退出),在這個信息裏,會解釋該進程爲何退出。
父進程得知子進程終結時,對該子進程使用wait系統調用,wait系統調用會取出子進程的退出信息,並清空該信息在內核中所佔據的空間。
可是,若是父進程早於子進程終結時,子進程就成了一個孤兒(orphand)進程。孤兒進程會被過繼給init進程。init進程會在該子進程終結時調用wait系統調用。
一個糟糕的程序也可能形成子進程的退出信息滯留在內核中的狀況(父進程不對子進程調用wait函數,內核中滯留task_struct結構體),這樣的狀況下,子進程成爲殭屍進程。當大量殭屍(Zombie)進程積累時,內存空間會被擠佔。