fflush(NULL) deadlock (C/C++)

案例代碼

#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>

void *func(void *arg)
{
  char str[50];
  FILE* fp = fdopen((int*)arg, "r");
  printf("fgets\n");
  fgets(str, 20, fp);
  exit(-1);
}

void main() {
  pthread_t ntid;
  int pipefd[2] = {0};

  if (pipe(pipefd) == -1)
  {
    perror("pipe");
  }
  pthread_create(&ntid, NULL, func, (void*)pipefd[0]);
  sleep(1);
  printf("fflush\n");
  fflush(NULL);
  close(pipefd[0]);
  close(pipefd[1]);
  printf("success\n");
}

現(xiàn)象

fflush(NULL) 卡死.
pstack 顯示卡在 __lll_lock_wait_private

調(diào)用棧信息:

Thread 2 (Thread 0x7ffff7dcf700 (LWP 8812)):
#0  0x00007ffff7ec1f84 in read () from /lib64/libc.so.6
#1  0x00007ffff7e51c98 in __GI__IO_file_underflow () from /lib64/libc.so.6
#2  0x00007ffff7e52dd6 in _IO_default_uflow () from /lib64/libc.so.6
#3  0x00007ffff7e4622a in _IO_getline_info () from /lib64/libc.so.6
#4  0x00007ffff7e4523f in fgets () from /lib64/libc.so.6
#5  0x000000000040122e in p ()
#6  0x00007ffff7fa14a7 in start_thread () from /lib64/libpthread.so.0
#7  0x00007ffff7ed13e3 in clone () from /lib64/libc.so.6
Thread 1 (Thread 0x7ffff7dd0740 (LWP 8811)):
#0  0x00007ffff7e551cb in __lll_lock_wait_private () from /lib64/libc.so.6
#1  0x00007ffff7e5382c in _IO_flush_all_lockp () from /lib64/libc.so.6
#2  0x00000000004011eb in thr_fn ()
#3  0x00000000004012b6 in main ()

原因分析

先看看 fflush 的官方描述

If the given stream was open for writing (or if it was open for updating and the last i/o operation was an output operation) any unwritten data in its output buffer is written to the file.
If stream is a null pointer, all such streams are flushed.

簡(jiǎn)單來(lái)說(shuō)就是 fflush 會(huì)刷新打開(kāi)的fd stream.
如果入?yún)⑹?code>NULL, 則刷新所有的fd sream.

再看看fgets

Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.

簡(jiǎn)單來(lái)說(shuō)佛析,fgets 會(huì)從給定的fd stream 讀取數(shù)據(jù)芥丧,并存入buffer.
但這里沒(méi)有說(shuō)到的一點(diǎn)是:fgets is a blocking read.
它會(huì)一直阻塞直到fd stream 有數(shù)據(jù)饵隙。

所以如果當(dāng)fd steam 沒(méi)有數(shù)據(jù)宵喂,又沒(méi)有結(jié)束,比如fd是一個(gè)還沒(méi)傳數(shù)據(jù)的pipe蜜氨,那么read這個(gè)動(dòng)作一直會(huì)阻塞在這個(gè)fd 上催享。
然后傅寡,當(dāng)fflush 嘗試去刷新這個(gè)fd時(shí)英岭,會(huì)因?yàn)槟貌坏芥i(鎖一直被read拿著)而一直阻塞湾盒。

解決辦法

應(yīng)該盡量避免在代碼中以阻塞的方式讀fd stream, 除非我們確定當(dāng)前一定有數(shù)據(jù)。
可以通過(guò)select, poll, epoll等異步I/O 來(lái)等到fd stream 有可用數(shù)據(jù)后诅妹,再去讀历涝,避免阻塞。

修改后的代碼

#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <poll.h>

void *func(void *arg)
{
  char str[50];
  FILE* fp = fdopen((int*)arg, "r");
  struct pollfd readFds = {0};
  readFds.fd = (int*)arg;
  readFds.events = POLLIN;

  printf("poll\n");
  if (0 < poll(&readFds, 1, -1))
  {
    printf("fgets\n");
    fgets(str, 20, fp);
  }
  exit(-1);
}

void main() {
  pthread_t ntid;
  int pipefd[2] = {0};

  if (pipe(pipefd) == -1)
  {
    perror("pipe");
  }
  pthread_create(&ntid, NULL, func, (void*)pipefd[0]);
  sleep(1);
  printf("fflush\n");
  fflush(NULL);
  close(pipefd[0]);
  close(pipefd[1]);
  printf("success\n");
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市荧库,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赵刑,老刑警劉巖分衫,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異般此,居然都是意外死亡蚪战,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門铐懊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)邀桑,“玉大人,你說(shuō)我怎么就攤上這事科乎”诨” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵茅茂,是天一觀的道長(zhǎng)捏萍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)空闲,這世上最難降的妖魔是什么令杈? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮碴倾,結(jié)果婚禮上逗噩,老公的妹妹穿的比我還像新娘。我一直安慰自己跌榔,他們只是感情好异雁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著矫户,像睡著了一般片迅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皆辽,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天柑蛇,我揣著相機(jī)與錄音,去河邊找鬼驱闷。 笑死耻台,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的空另。 我是一名探鬼主播盆耽,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了摄杂?” 一聲冷哼從身側(cè)響起坝咐,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎析恢,沒(méi)想到半個(gè)月后墨坚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡映挂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年泽篮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柑船。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡帽撑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鞍时,到底是詐尸還是另有隱情亏拉,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布寸癌,位于F島的核電站专筷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蒸苇。R本人自食惡果不足惜磷蛹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溪烤。 院中可真熱鬧味咳,春花似錦、人聲如沸檬嘀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鸳兽。三九已至掂铐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揍异,已是汗流浹背全陨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衷掷,地道東北人辱姨。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像戚嗅,于是被迫代替她去往敵國(guó)和親雨涛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枢舶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,454評(píng)論 0 13
  • 函數(shù)調(diào)用 Built-in Functions abs(x) Return the absolute value ...
    叫我七夜閱讀 1,170評(píng)論 0 0
  • 大綱 一.Socket簡(jiǎn)介 二.BSD Socket編程準(zhǔn)備 1.地址 2.端口 3.網(wǎng)絡(luò)字節(jié)序 4.半相關(guān)與全相...
    VD2012閱讀 2,344評(píng)論 0 5
  • 生活阿,其實(shí)沒(méi)有我們想象的那么好替久,它是很復(fù)雜的凉泄,也有很多傷心。那些活得很好的人從來(lái)就不是因?yàn)樗麄兊纳钣卸嗝篮茫?..
    nia你阿閱讀 267評(píng)論 0 1
  • 屏讀 Screening 在古代文化都是圍繞言語(yǔ)的侣肄。我們?cè)?jīng)是言語(yǔ)之民(People of the word)旧困。大...
    loyanda閱讀 278評(píng)論 0 2