UNIX系統支持在不同進程間共享打開文件。內核使用3種數據結構表示打開文件,它們之間的關系決定了文件共享方面一個進程對另一個進程可能產生的影響。
內核維持了3個表,即進程表,文件表和v節點表。具體如下:
1>每個進程在進程表中都有一個紀錄項,記錄項中包含一張打開文件描述符表,每個描述符占用一項。與每個文件描述符相關聯的是:
a. 文件描述符標志(close_on_exec);
b. 指向一個文件表項的指針。
2>內核為所有打開文件維持一張文件表。每個文件表項包含:
a. 文件狀態標志(讀、寫、添寫、同步和非阻塞等);
b. 當前文件偏移量;
c. 指向該文件v節點表項的指針。
3>每個打開文件(或設備)都有一個v節點(v-node)結構。v節點包含了文件類型和對此文件進行各種操作函數的指針。對於大多數文件,v節點還包含了該文件的i節點(i-node,索引節點),這些信息是在打開文件是從磁盤上讀入內存用的。i節點包含了文件的所有者、文件長度、指向文件實際數據塊在磁盤上所在位置的指針。(UNIX文件系統中有更多關於i節點的介紹。另,Linux沒有使用v節點,而是采用了一個與文件系統相關的i節點和一個與文件系統無關的i節點)
圖1 打開文件的內核數據結構
上圖顯示了一個進程對應的3張表之間的關系。該進程有兩個不同打開文件:一個文件從標准輸入打開(文件描述符0),另一個文件從標准輸出打開(文件描述符1)。
圖2 兩個獨立進程各自打開同一個文件
一個現有的進程可以調用fork函數創建一個新進程。由fork進程創建的進程稱為子進程,frok函數調用一次,返回兩次。子進程的返回值是0,父進程的返回是子進程的進程ID。子進程和父進程繼續執行fork調用之後的指令。(兩個都會執行,但是執行先順序不定,這取決於內核所使用的調度算法。) 子進程是父進程的副本,如子進程獲得父進程數據空間、堆和棧的副本。父進程與子進程並不共享存儲空間,但共享正文段。但許多實現並不執行父進程數據的完全副本,而是使用寫時復制(Copy-On-Write, COW)技術。
下列代碼中可以看到子進程對變量所做的改變並不影響父進程中該變量的值。
#include "apue.h"
int glob = 6;
char buf[] = "a write to stdout\n";
int
main(void)
{
int var;
pid_t pid;
var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
err_sys("write error");
printf("before fork\n");
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) {
glob++;
var++;
} else {
sleep(2);
}
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
}
如果執行該程序,則可得到:
可以看到,第一次為直接執行,輸出到標准輸出;而第二次重定向到文件了。導致兩次執行同樣的代碼,得到的結果卻不同。我們知道,文件I/O函數是不帶緩沖的,標准I/O庫是帶緩沖的。而標准輸出連接到終端設備,則它是行緩沖的;否則它是全緩沖的。第一次執行中,printf函數輸出到標准輸出,緩沖區由換行符沖洗。而重定向到文件時,緩沖區是全緩沖的,在fork調用之前調用了printf一次。但當調用fork時,該行數據仍在緩沖區中,然後再將父進程數據空間復制到子進程中時,該緩沖區數據也被復制到子進程中,此時父進程和子進程各自有個帶該行的緩沖區。在exit之前的第二個printf將其數據追加到已有的緩沖區中。當進程終止時,其緩沖區中的內容都被寫到相應文件中。
對上述程序,需要注意的一點是:在重定向父進程的標准輸出時,子進程的標准輸出也被重定向。fork的一個特性是父進程所有打開文件描述符都復制到子進程中。父進程和子進程每個相同的打開描述符共享一個文件表項。重要的一點是,父進程和子進程共享同一個文件偏移量。
Unix環境高級編程 源代碼地址 http://www.linuxidc.com/Linux/2011-04/34826.htm
Unix環境高級編程源碼編譯 http://www.linuxidc.com/Linux/2011-09/42503.htm
apue.h頭文件(Unix環境高級編程) http://www.linuxidc.com/Linux/2012-01/51729.htm
《Unix環境高級編程》(第二版)apue.h的錯誤 http://www.linuxidc.com/Linux/2011-04/34662.htm
Unix環境高級編程第二版讀書筆記 http://www.linuxidc.com/Linux/2011-04/34235.htm
《Unix環境高級編程》中apue.h的問題 http://www.linuxidc.com/Linux/2013-01/77686.htm