3 回答

TA貢獻1816條經驗 獲得超4個贊
(結合用戶@Jack的注釋中的一些解釋)當您將某些內容打印到“標準輸出”標準輸出(通常是計算機監(jiān)視器,盡管您可以將其重定向到文件)時,它最初會存儲在臨時緩沖區(qū)中。
分叉的兩面都繼承未刷新的緩沖區(qū),因此,當分叉的每一面觸及return語句并結束時,都會刷新兩次。
在分叉之前,應該fflush(stdout);
先刷新緩沖區(qū),以使子代不會繼承該緩沖區(qū)。
屏幕上的stdout(而不是將其重定向到文件時)實際上是由行尾緩沖的,因此,如果您這樣做了printf("Hi\n");
,則不會有此問題,因為它會刷新緩沖區(qū)本身。

TA貢獻1804條經驗 獲得超8個贊
printf("Hi");并不會立即在屏幕上顯示“ Hi”一詞。它所做的是在stdout緩沖區(qū)中填充單詞“ Hi”,一旦緩沖區(qū)“被刷新”,該字詞就會顯示出來。在這種情況下,stdout指向您的顯示器(假定)。在這種情況下,緩沖區(qū)將在緩沖區(qū)已滿,強制您刷新或(最常見)打印換行符(“ \ n”)時刷新。由于在fork()調用時緩沖區(qū)仍然充滿,因此父進程和子進程都繼承該緩沖區(qū),因此在刷新緩沖區(qū)時,它們都將打印出“ Hi”。如果fflush(stout);在調用fork之前先調用,它應該可以工作:
int main() {
printf("Hi");
fflush(stdout);
fork();
return 0;
}
另外,正如我所說,如果您在其中包含換行符,printf那么它也應該可以正常工作:
int main() {
printf("Hi\n");
fork();
return 0;
}

TA貢獻1877條經驗 獲得超6個贊
通常,在fork()兩側的庫中使用開放的句柄/對象是非常不安全的。
這包括C標準庫。
fork()使兩個進程合二為一,沒有庫可以檢測到它的發(fā)生。因此,如果兩個進程繼續(xù)使用相同的文件描述符/套接字等運行,它們現(xiàn)在將具有不同的狀態(tài),但共享相同的文件句柄(從技術上講,它們具有副本,但具有相同的基礎文件)。這使壞事發(fā)生。
fork()導致此問題的情況的示例
stdio,例如tty輸入/輸出,管道,光盤文件
數(shù)據(jù)庫客戶端庫使用的套接字
服務器進程使用的套接字-當為一個套接字提供服務的孩子碰巧繼承了文件的句柄時,可能會產生奇怪的效果-正確地進行這種編程是很棘手的,請參閱Apache的源代碼示例。
在一般情況下如何解決此問題:
要么
a)在fork()之后,可能立即在同一二進制文件上調用exec()(帶有必要的參數(shù)以完成您打算做的任何工作)。這很容易。
b)分叉之后,請勿使用任何依賴于它們的現(xiàn)有打開的句柄或庫對象(可以打開新的句柄);盡快完成工作,然后調用_exit()(而不是exit())。不要從調用fork的子例程中返回,因為那樣可能會導致調用C ++析構函數(shù)等,這可能會對父進程的文件描述符造成不良影響。這相當容易。
c)分叉之后,在讓孩子繼續(xù)之前,以某種方式清理所有物體并使它們都處于健全狀態(tài)。例如,關閉基礎文件描述符,而不刷新父緩沖區(qū)中重復的緩沖區(qū)中的數(shù)據(jù)。這很棘手。
c)大約是Apache所做的。
- 3 回答
- 0 關注
- 620 瀏覽
添加回答
舉報