進程創建函數fork()、vfork() ,以及excel()函數
一、進程的創建步驟以及創建函數的介紹
1、使用fork()或者vfork()函數創建新的進程
2、條用exec函數族修改創建的進程。使用fork()創建出來的進程是當前進程的完全復制,然而我們創建進程是為了讓新的進程去執行新的程序,因此,就需要用到exec函數族對創建出來的新進程進行修改,讓他擁有和父進程不一樣的東西,修改后就可以執行新的程序,當然,修改后的子進程包含了要執行程序的信息。
在Linux中,fork()和vfork()就是用于創建進程的兩個函數,他們的相關信息如下:
創建進程函數:
pid_t fork(void)//成功返回0,失敗返回-1
fork()用于創建新的進程,所創建進程為當前進程的子進程,可以通過fork()函數的返回質6來控制進程是在父進程中還是在子進程中。如果運行在父進程中,則返回PID為子進程的進程號,如果在子進程中,則返回的PID為0
pid_t vfork(void)//成功返回0,失敗返回-1
vfork()函數和fork()函數比較類似,都用于創建子進程。只是其用于創建新的進程,父子進程共享虛擬內存空間。然而在內核中,vfork()的實現任然調用fork()函數,調用函數如下:
sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL);
}
在上述函數中,pid_t為隱含類型,實際上就是一個int的類型。隱含類型只數據類型的物理表示是未知的或者是不相關的
二、實現過程和區別
1、Linux是通過_cloen()系統調用來實現fork()的,這一調用通過一系列的參數標志來指明父子進程需要的資源。Fork(),vfork(),_cloen()庫函數都根據各自需要的參數標志去調用cloen(),然后由cloen()去調用do_fork()函數,do_fork()函數也就是真正的創建進程的函數。他完成了創建進程的大部分工作。同時他還會調用copy_process()函數。然后讓進程開始運行。
2、vfork()和fork()的功能相同,除了不拷貝父進程的頁表項,也就是說不會復制和父進程相關的資源,父子進程將共享地址空間,子進程對虛擬內存空間的任何實際修改實際上是在修改父進程虛擬內粗空間的內容。并且其父進程會被阻塞,直到子進程退出或者執行exec()函數族.這樣由于父子進程共享地址空間,避免了fork在資源復制是的消耗。
3、寫時copy機制:Linux系統采用了“些操作時復制”的方法,其是一種延遲資源復制的方法,子進程在創建的時候并不復制父進程的相關資源,父子進程通過訪問相同的物理內存來偽裝已經實現了的對資源的復制。這種共享是制度方式是只讀方式,這一點與vfork是不同的,當子進程對內存數據存在這些的操作時,才會進香資源的復制。正是由于這種機制的出現,vfork()好像已經沒有什么作用了。
三、在進程窗創建過程中copy_process()函數完成的工作//摘自:Linux內核設計與實現
1、調用dup_task_struct()為心進程創建一個內核棧、thread_info結構和task_struct,這些值與當前進程的值相同。此時,子進程和父進程的描述符完全相同。
2、檢查新創建的這個子進程后,當前用戶所用有的進程數目沒有超過給他分配的資源的限制
3、現在,子進程著手使自己與父進程區別開來,進程描述符內的許多成員都要被清0或者設置初始值。進程描述符的成員值并不是繼承而來的,而主要是統計信息,進程描述符中的大多數數據都是共享的。
4、接下來,子進程的狀態被設置為不可終端等待狀態以保證他不會投入運行
5、copy_process()調用copy_flags()以更新task_struct的flags成員。表明進程是擁有超級用戶權限的PF_SUPER[RIV標志被清0。表明進程還沒有調用exec()函數的PE_FORKNOEXEC標志被設置。
6、調用get_pid()為新進程獲取一個有效的PID
7、根據傳給cloen()的參數標志copy_process()拷貝或者共享打開的文件、文件系統信、信號處理函數、進程地址空間和命名空間等。
8、讓父進程和子進程平分剩余的時間片。
9、最后,copy_proccess()做掃尾工作并返回一個只想子進程的指針。
相關函數:fork, execle, execlp, execv, execve, execvp
表頭文件:#include
函數定義:int execl(const char *path, const char *arg, ...);
函數說明:execl()用來執行參數path字符串所代表的文件路徑, 接下來的參數代表執行該文件時傳遞的argv[0],argv[1].....是后一個參數必須用空指針NULL作結束
返回值 :成功則不返回值, 失敗返回-1, 失敗原因存于errno中
錯誤代碼:參execve()
范例:
- [
- /* 執行 /bin/ls -al /ect/passwd */
- #include <unistd.h>
- /**
- * File: execl.c
- *
- */
- main()
- {
- execl("/bin/ls", "ls", "-al", "/etc/passwd", (char *) 0);
- }
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成