1.在Linux中進程的創建方式
在linux系統中,新的進程是通過已存在的父進程復制而來的。
- 當一個子進程被成功創建,其虛擬地址空間的信息與其父進制的虛擬空間信息是相同的(這意味著它們的代碼和數據是一致的)。
- 通過執行exec系列的函數,可以用一個新程序的虛擬地址空間信息來更新子進程的虛擬地址空間信息。
2.fork函數原理
2.1 fork函數原型
pid_t fork(void);
功能:創建一個新的進程。
參數:
無。
返回值:
fork函數調用一次返回兩次。
-
父進程:返回子進程PID。
-
子進程:返回0。
-
失敗:返回-1。
2.2 fork函數實現原理
2.3 父子進程虛擬地址空間(mm_struct)之間的關系
- 父子進程各自擁有自己獨立的虛擬地址空間。
- 父子進程共享代碼段(只讀)。
- 采用寫時拷貝(copy-on-write)技術創建子進程虛擬地址空間。
2.4 寫時拷貝(copy-on-write)技術
傳統fork函數缺點:
- 復制子進程虛擬地址空間時,存在大量拷貝,效率很低。
- 子進程立馬需要執行execv函數替換虛擬地址空間內容,導致上一步復制子進程虛擬地址空間變得多余。
什么是寫時拷貝?
寫時拷貝是指父進程在創建子進程時,只創建虛擬地址空間,不為子進程分配實際的內存,父進程和子進程之間共享相同的物理內存頁面。
當父進程或者子進程對虛擬地址空間對應的內存進行修改時才會分配實際內存。
寫時拷貝技術優點:
- 節省內存開銷。
- 提高創建進程效率。
拷貝前
拷貝后
2.5 父子進程如何共享文件(files_struct)
FD_CLOSEXEC文件標志?
子進程和父進程共享文件是一種不安全的行為,如果子進程調用exec家族函數,子進程的虛擬機制空間被新的程序替換,如果子進程還保留父進程的文件描述符表,后果很嚴重。
文件設置FD_CLOSEXEC文件標志后,子進程調用exec家族函數,該文件會被關閉。
如何設置FD_CLOSEXEC文件標志?
- 方法1:open函數帶上O_CLOSEXEC標志。
如:open(“file”, O_RDWR | O_CREAT | O_TRUNC | O_CLOSEXEC, 0644 );
- 方法2:fcntl函數F_SETFD操作設置。
3.vfork函數原理
3.1 vfork函數原型
pid_t vfork(void);
功能:fork函數創建一個新的子進程,該子進程與父進程共享相同的地址空間。
參數:
無。
返回值:
vfork函數調用一次返回兩次。
- 父進程:返回子進程PID。
- 子進程:返回0。
- 失敗:返回-1。
3.2 vfork和fork函數區別?
- vfork函數創建子進程和父進程共享地址空間。
- 使用vfork函數創建的子進程則會暫停父進程的執行,直到子進程調用exec()或者_exit()函數退出或替換自己的地址空間。
不推薦使用vfork函數!!!
vfork函數由于子進程和父進程共享地址空間,vfork比傳統fork函數效率高。隨著寫時復制技術出現,這個優勢已經不存在了。
vfork存在不安全的行為,所以不推薦使用vfork函數。