程序是所有作業系統的核心概念,同樣在linux上也不例外。
主要内容:
程序和線程
程序的生命周期
程序的建立
程序的終止
程序和線程是程式運作時狀态,是動态變化的,程序和線程的管理操作(比如,建立,銷毀等)都是有核心來實作的。
Linux中的程序于Windows相比是很輕量級的,而且不嚴格區分程序和線程,線程不過是一種特殊的程序。
是以下面隻讨論程序,隻有當線程與程序存在不一樣的地方時才提一下線程。
程序提供2種虛拟機制:虛拟處理器和虛拟記憶體
每個程序有獨立的虛拟處理器和虛拟記憶體,
每個線程有獨立的虛拟處理器,同一個程序内的線程有可能會共享虛拟記憶體。
核心中程序的資訊主要儲存在task_struct中(include/linux/sched.h)
程序辨別PID和線程辨別TID對于同一個程序或線程來說都是相等的。
Linux中可以用ps指令檢視所有程序的資訊:
程序的各個狀态之間的轉化構成了程序的整個生命周期。
<a href="http://images.cnblogs.com/cnblogs_com/wang_yb/201208/201208201741296349.png"></a>
Linux中建立程序與其他系統有個主要差別,Linux中建立程序分2步:fork()和exec()。
fork: 通過拷貝目前程序建立一個子程序
exec: 讀取可執行檔案,将其載入到記憶體中運作
建立的流程:
調用dup_task_struct()為新程序配置設定核心棧,task_struct等,其中的内容與父程序相同。
check新程序(程序數目是否超出上限等)
清理新程序的資訊(比如PID置0等),使之與父程序差別開。
新程序狀态置為 TASK_UNINTERRUPTIBLE
更新task_struct的flags成員。
調用alloc_pid()為新程序配置設定一個有效的PID
根據clone()的參數标志,拷貝或共享相應的資訊
做一些掃尾工作并傳回新程序指針
建立程序的fork()函數實際上最終是調用clone()函數。
建立線程和程序的步驟一樣,隻是最終傳給clone()函數的參數不同。
比如,通過一個普通的fork來建立程序,相當于:clone(SIGCHLD, 0)
建立一個和父程序共享位址空間,檔案系統資源,檔案描述符和信号處理程式的程序,即一個線程:clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)
在核心中建立的核心線程與普通的程序之間還有個主要差別在于:核心線程沒有獨立的位址空間,它們隻能在核心空間運作。
這與之前提到的Linux核心是個單核心有關。
和建立程序一樣,終結一個程序同樣有很多步驟:
子程序上的操作(do_exit)
設定task_struct中的辨別成員設定為PF_EXITING
調用del_timer_sync()删除核心定時器, 確定沒有定時器在排隊和運作
調用exit_mm()釋放程序占用的mm_struct
調用sem__exit(),使程序離開等待IPC信号的隊列
調用exit_files()和exit_fs(),釋放程序占用的檔案描述符和檔案系統資源
把task_struct的exit_code設定為程序的傳回值
調用exit_notify()向父程序發送信号,并把自己的狀态設為EXIT_ZOMBIE
切換到新程序繼續執行
子程序進入EXIT_ZOMBIE之後,雖然永遠不會被排程,關聯的資源也釋放掉了,但是它本身占用的記憶體還沒有釋放,
比如建立時配置設定的核心棧,task_struct結構等。這些由父程序來釋放。
父程序上的操作(release_task)
父程序受到子程序發送的exit_notify()信号後,将該子程序的程序描述符和所有程序獨享的資源全部删除。
從上面的步驟可以看出,必須要確定每個子程序都有父程序,如果父程序在子程序結束之前就已經結束了會怎麼樣呢?
子程序在調用exit_notify()時已經考慮到了這點。
如果子程序的父程序已經退出了,那麼子程序在退出時,exit_notify()函數會先調用forget_original_parent(),然後再調用find_new_reaper()來尋找新的父程序。
find_new_reaper()函數先在目前線程組中找一個線程作為父親,如果找不到,就讓init做父程序。(init程序是在linux啟動時就一直存在的)
本文轉自wang_yb部落格園部落格,原文連結:http://www.cnblogs.com/wang_yb/archive/2012/08/20/2647912.html,如需轉載請自行聯系原作者