linux fork 目录,linux fork()理解
各位同學,轉換下思維,這里說的是“進程”, 不是“線程”,OK,我們開始
“進程”二字似乎總有那么些“只可意會不可言傳”的韻味,維基百科是這樣來解釋的:
進程(英語:Process,臺灣譯作行程)是計算機中已運行程序的物理。進程本身不會運行,是線程的容器。程序本身只是指令的集合,進程才是程序(那些指令)的真正運行。若干進程有可能與同一個程序相關系,且每個進程皆可以同步(循序)或不同步(平行)的方式獨立運行(多線程即每一個線程都代表一個進程)。現代計算機系統可在同一段時間內加載多個程序和進程到存儲器中,并借由時間共享(或稱多任務),以在一個處理器上表現出同時(平行性)運行的感覺。同樣的,使用多線程技術的操作系統或計算機架構,同樣程序的平行進程,可在多 CPU 主機或網絡上真正同時運行(在不同的 CPU 上)。進程為現今分時系統的基本運作單位。
也有朋友如此來闡述,
一個可以執行的程序;
和該進程相關聯的全部數據(包括變量,內存空間,緩沖區等等);
程序的執行上下文(execution context)
我更希望將這些簡化一下(或許不太準確):指令和執行指令所需的環境,指令可以理解成“代碼”,環境可以理解成“上下文”
系統用一個叫做“進程表”的東西來維護中系統中的進程,進程表中的一個條目維護著存儲著一個進程的相關信息,比如進程號,進程狀態,寄存器值等等...
當分配給進程A的“時間片”使用完時,CPU會進行上下文切換以便運行其他進程,比如進程B,這里所謂的“上下文切換”,主要就是在操作那個“進程表”,其將進程A的相關信息(上下文)保存到其對應的進程表項中, 與之相反,其會從對應于進程B的進程表項中讀取相關信息并運行之。
那么,如果進程A新建了一個進程C呢?教程表會多這樣一個表項,并且該表項擁有一個唯一的ID,也就是進程號(PID),進程表項的其他值大部分與進程A的相同,具體說來,就是C和A共享代碼段,并且C將A的數據空間,堆棧等復制一份 ,然后從A創建C的地方開始運行。The new process (child process) is an exact copy of the calling process (parent process) except as detailed below.
The child process has a unique process ID.
The child process ID also does not match any active process group ID.
The child process has a different parent process ID (that is, the process ID of the parent process).
The child process has its own copy of the parent's file descriptors. Each of the child's file descriptors refers to the same open file description with the corresponding file descriptor of the parent.
The child process has its own copy of the parent's open directory streams. Each open directory stream in the child process may share directory stream positioning with the corresponding directory stream of the parent.
The child process may have its own copy of the parent's message catalogue descriptors.
The child process' values of?tms_utime,?tms_stime,?tms_cutime?and?tms_cstime?are set to 0.
The time left until an alarm clock signal is reset to 0.
All?semadj?values are cleared.
File locks set by the parent process are not inherited by the child process.
The set of signals pending for the child process is initialised to the empty set.
Interval timers are reset in the child process.
If the Semaphores option is supported, any semaphores that are open in the parent process will also be open in the child process.
If the Process Memory Locking option is supported, the child process does not inherit any address space memory locks established by the parent process via calls to?mlockall()?or?mlock().
Memory mappings created in the parent are retained in the child process. MAP_PRIVATE mappings inherited from theparent will also be MAP_PRIVATE mappings in the child, and any modifications to the data in these mappings made by the parent prior to calling?fork()will be visible to the child. Any modifications to the data in MAP_PRIVATE mappings made by the parent after?fork()?returns will be visible only to the parent. Modifications to the data in MAP_PRIVATE mappings made by the child will be visible only to the child.
If the Process Scheduling option is supported, for the SCHED_FIFO and SCHED_RR scheduling policies, the child process inherits the policy and priority settings of the parent process during a?fork()?function. For other scheduling policies, the policy and priority settings on?fork()are implementation-dependent.
If the Timers option is supported, per-process timers created by the parent are not inherited by the child process.
If the Message Passing option is supported, the child process has its own copy of the message queue descriptors of the parent. Each of the message descriptors of the child refers to the same open message queue description as thecorresponding message descriptor of the parent.
If the Asynchronous Input and Output option is supported, no asynchronous input or asynchronous output operations are inherited by the child process.
從代碼角度來看,創建一個新進程的函數聲明如下:
pid_t?fork(void);
其包含在 unistd.h 頭文件中,其中pid_t是表示“type of process id”的32位整數, 至于函數的返回值,取決于在哪個進程中來檢測該值,如果是在新創建的進程中,其為0;如果是在父進程中(創建新進程的進程),其為新創建的進程的id; 如果創建失敗,則返回負值。
我們看下面的代碼:
#include#includeintmain?()
{
printf("app?start...\n");
pid_t?id=fork();if(id<0)?{
printf("error\n");
}elseif(id==0)?{
printf("hi,?i'm?in?new?process,?my?id?is?%d?\n",?getpid());
}else{
printf("hi,?i'm?in?old?process,?the?return?value?is?%d\n",?id);
}return0;
}
為了方便理解,我在上面使用了getpid函數,其返回當前進程的id。
程序輸出為:
app?start...hi,i'm?in?old?process,the?return?value?is5429hi,i'm?in?new?process,my?id?is5429
另外,看到不少資料上說“fork函數是少數返回兩個值的函數”,我不贊成該說法,我猜想,其之所以看上去有著不同的值,是系統創建新進程并復制父進程相關資源時,故意根據創建狀態放入了不同的值。
fork函數失敗的原因主要是沒有足夠的資源來進行創建或者進程表滿,如果是非root權限的賬戶,則可能被管理員設置了最大進程數。一個用戶所能創建的最大進程數限制是很重要的,否則一句代碼就可能把主機搞當機:for(;;) fork();
再看下面的代碼:
#include#includeintmain?()
{
printf("app?start...\n");intcounter=0;
fork();
counter++;
printf("the?counter?value?%d\n",?counter);return0;
}
輸出如下:
app?start...
the?counter?value1the?counter?value1
之所以會這樣,畫個圖就明白了:
?
并且,新進程得到的是父進程的副本,所以,父子進程counter變量不會相互影響。
再來一個demo:
#include#includeintmain?()
{
printf("app?start...");
fork();return0;
}
輸出為:
app?start...app?start...
好奇怪是吧?情況是這樣的:
當你調用printf時,字符串被寫入stdout緩沖區(還沒刷到屏幕上的哦),然后fork,子進程復制了父進程的緩沖區,所以子進程的stdout緩沖區中也包含了“app start ...”這個字符串,然后父子進程各自運行,當他們遇到return語句時,緩沖器會被強制刷新,然后就分別將“app start...”刷到了屏幕上。如果想避免,在fork前,調用fflush強制刷新下緩沖區就可以了,在字符串后面加上“\n”也可以,因為stdout是按行緩沖的。
總結
以上是生活随笔為你收集整理的linux fork 目录,linux fork()理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摩尔庄园手游小镇钓鱼在哪里?
- 下一篇: linux 为什么 c语言,为什么C程序