UNIX緩衝機制

2021-09-01 10:47:53 字數 2640 閱讀 4615

某日一朋友寫了乙個hello world**,出不來結果,**如下:

#include int  main(int argc, char **argv)

注意到,在**中printf語句列印的字串最後沒有帶換行符,而且最後呼叫了_exit函式,這導致了在終端螢幕上顯示不出來字串"hello world!"。

首先介紹一下unix裡面關於標準io的幾種緩衝機制:

1、全緩衝 。全緩衝指的是系統在填滿標準io緩衝區之後才進行實際的io操作;注意,對於駐留在磁碟上的檔案來說通常是由標準io庫實施全緩衝。

2、行緩衝 。在這種情況下,標準io在輸入和輸出中遇到換行符時執行io操作;注意,當流涉及終端的時候,通常使用的是行緩衝。

3、無緩衝 。無緩衝指的是標準io庫不對字元進行緩衝儲存;注意,標準出錯流stderr通常是無緩衝的。 

其次介紹一下幾個退出函式:

1、exit ()。呼叫exit函式之後,它首先會執行一系列的清理處理,隱含會對

儲存在緩衝區內的資料進行沖洗,包括呼叫執行各終止處理程式,關閉所有標準io流等,然後進入核心。

2、_exit ()。與exit不同的是,它不進行清理工作而直接進入核心。此函式由posix.1說明,放在unistd.h裡面。

3、_exit ()。同樣,它也不進行清理工作而直接進入核心。此函式跟exit一樣由iso c說明,放在stdlib.h裡面。

現在回過頭來看上面的那段**,很容易發現,由於printf函式是行緩衝的(因為它要往終端輸出資料),而且要列印的字串不帶換行符,因此在它沒有遇到換行符或者沒有填滿緩衝區之前不會進行實際的io操作,而緊接下來的_exit函式又立即進入核心沒有處理io緩衝區,所以我們在終端上看不到hello world語句。

下面介紹設定檔案緩衝區函式

void setbuf(file *stream,char *buf);

void setvbuf(file *stream,char *buf,int type,unsigned size);

這兩個函式將使得開啟檔案後,使用者可建立自己的檔案緩衝區,而不使用fopen()函式開啟檔案設定的預設緩衝區。  

對於setbuf()函式,buf指出的緩衝區長度由標頭檔案stdio.h中定義的巨集bufsize的值決定,預設值為512位元組。當選定buf為空時,setbuf函式將使的檔案i/o不帶緩衝。而對setvbuf函式,則由malloc函式來分配緩衝區。引數size指明了緩衝區的長度(必須大於0),而引數type則表示了緩衝的型別,其值可以取如下值:

type 值 含義

_iofbf 檔案全部緩衝,即緩衝區裝滿後,才能對檔案讀寫

_iolbf 檔案行緩衝,即緩衝區接收到乙個換行符時,才能對檔案讀寫

_ionbf 檔案不緩衝,此時忽略buf,size的值,直接讀寫檔案,不再經過檔案緩衝區緩衝

在《c陷阱和缺陷》一書中,講到乙個setbuf的陷阱:

程式輸出有兩種方式:一種是即時處理方式,另一種是先暫存起來,然後再大塊寫入的方式,前者往往造成較高的系統負擔。因此,c語言實現通常都允許程式設計師進行實際的寫操作之前控制產生的輸出資料量。

這種控制能力一般是通過庫函式setbuf實現的。如果buf是乙個大小適當的字元陣列,那麼:

setbuf(stdout,buf);

語句將通知輸入/輸出庫,所有寫入到stdout的輸出都應該使用buf作為輸出緩衝區,直到buf緩衝區被填滿或者程式設計師直接呼叫fflush(譯註:對於由寫操作開啟的檔案,呼叫fflush將導致輸出緩衝區的內容被實際地寫入該檔案),buf緩衝區中的內容才實際寫入到stdout中。緩衝區的大小由系統標頭檔案中的bufsiz定義。

下面的程式的作用是把標準輸入的內容複製到標準輸出中,演示了setbuf庫函式最顯而易見的用法:

#include

main()

int c;

char buf[bufsiz];

setbuf(stdout, buf);

while((c=getchar())!=eof)

putchar(c);

遺憾的是,這個程式是錯誤的,僅僅是因為乙個細微的原因。程式中對庫函式setbuf的呼叫,通知了輸入/輸出庫所有字元的標準輸出應該首先快取在buf中。要找到問題出自何處,我們不妨思考一下buf緩衝區最後一次被清空是在什麼時候?答案是在main函式結束之後,作為程式交回控制給作業系統之前c執行時庫所必須進行的清理工作的一部分。但是,在此之前buf字元陣列已經被釋放!

要避免這種型別的錯誤有兩種辦法。第一種辦法是讓緩衝陣列成為靜態陣列,既可以直接顯式宣告buf為靜態:

static char buf[bufsiz];

也可以把buf宣告完全移到main函式之外。第二種辦法是動態分配緩衝區,在程式中並不主動釋放分配的緩衝區(譯註:山於緩衝區是動態分配的,所以main函式結束時並不會釋放該緩衝區,這樣c執行時庫進行清理工作時就不會發生緩衝區已釋放的情況):

char *malloc();

setbuf(stdout,malloc(bufsiz));

如果讀者關心一些程式設計「小技巧」,也許會注意到這裡其實並不需要檢查malloc函式呼叫是否成功。如果malloc函式呼叫失敗,將返回乙個null指標。setbuf函式的第二個引數取值可以為null,此時標準輸出不需要進行緩衝。這種情況下,程式仍然能夠工作,只不過速度較慢而已。

UNIX緩衝機制

某日一朋友寫了乙個hello world 出不來結果,如下 include int main int argc,char argv 注意到,在 中printf語句列印的字串最後沒有帶換行符,而且最後呼叫了 exit函式,這導致了在終端螢幕上顯示不出來字串 hello world 首先介紹一下unix...

UNIX裡面關於標準IO的幾種緩衝機制

編寫背後 國嵌的那段時間,老范曾讓我們幫回答下論壇某個會員的問題,問題 出不來結果,沒任何列印資訊 如下 i nclude main 注意到,在 中printf語句列印的字串最後沒有帶換行符,而且最後呼叫了 exit函式,這導致了在終端螢幕上顯示不出來列印資訊。首先介紹一下unix裡面關於標準io的...

訊息緩衝機制

訊息緩衝是unix系統程序之間進行大量資料交換的機制之一。訊息緩衝是基於訊息佇列的。傳送程序將訊息掛入接收程序的訊息佇列,接收程序從訊息佇列中接收訊息。訊息是指具有型別和數量的乙個資料。訊息分共有和私有的,如果訊息為私有的,只能被建立訊息佇列的程序和其子程序訪問 如果是公有的,可以被系統中知道訊息佇...