作者yoco315 (眠月)
看板Programming
標題Linux 上面讀取檔案發生超奇怪問題
時間Mon Apr 13 14:27:54 2009
※ [本文轉錄自 C_and_CPP 看板]
作者: yoco315 (眠月) 看板: C_and_CPP
標題: Linux 上面讀取檔案發生超奇怪問題
時間: Mon Apr 13 14:26:36 2009
我遭遇到一個很奇怪的問題,希望有經驗的人可以給我一點建議。
敝人服務的單位現在有個程式,讓我們叫他 master 好了。
這個 master 會透過 lsf/grid 在內部網路上的其他機器建立 slave 程式執行。
有點像 client/server 架構(根本就是嘛)。
這中間,master 跟 slave 需要交換資料,
交換的資料,我們都是透過 data 檔案的讀寫來完成。
而 master 跟 slave 的同步化,也是透過檔案來完成。
當 master 要告訴 slave 可以開始的時候,就會寫一個特殊的 flag 檔案,
這段時間 slave 就是不斷的 polling 去看那個檔案能不能讀了。
當然 slave 中間每一次會 sleep(1) 以避免 CPU 一直在工作。
當需要接受資料的那一方,發現一個特殊檔案已經存在了,
那表示他需要讀取的檔案已經備妥了,他就會去開啟那個檔案來讀取需要的資料。
以時間軸來畫圖的話大概就是這樣
Master Slave(s) 可能有好幾個
---------------------------------------------------------
寫資料檔 (polling檢查flag檔案)
寫 flag ↓
(polling) 發現 flag 檔案
↓ 開啟 data 檔案讀取資料
↓ (進行計算...)
↓ 寫 data 檔案
↓ 寫 flag 檔通知 master
發現 flag 檔案 (polling)
開檔,讀取 ↓
(計算) ↓
sync 的時候我們可以說平均每次會浪費掉 0.5 秒在等待,
因為中間的 sync 次數不少,所以累積起來就是一段時間,
為了改善這個部份,所以 sync 的部份就想改成用 socket 來做。
這部分我已經完成了。
果然省掉 pooling 的等待時間,效率就上升了,
Master Slave(s) 可能有好幾個
---------------------------------------------------------
寫資料檔 (block read() 接封包)
送封包 ↓
(polling) 收到封包
(block read() 接封包) 開啟 data 檔案讀取資料
↓ (進行計算...)
↓ 寫 data 檔案[1]
↓ 送封包
收到封包 (block read() 接封包)
開檔,讀取[2] ↓
(計算) ↓
(只有把用檔案做同步化的地方改成用 socket)
問題是現在遇到一個超奇怪的問題。
當 [1] 的地方,已經把檔案寫好了,而且也 fclose() 關閉檔案了。
在 [2] 的地方,fopen 有拿到東西,不是 NULL,但是當我要讀取的時候,卻什麼也讀不到。
我呼叫 perror(),系統給的錯誤訊息是「No such file or directory.」
問題是我開檔的時候明明開到了!
事情真的很奇怪,
這個現象不是永遠都發生,只有「有時候」發生。
如果我在 [2] 之前 sleep() 一段時間,
那我就可以順利讀取到檔案。
又,
我發現這個現象只有在我的 slave 是透過 system() 啟動的時候才會發生,
(因為我要派到那台機器上的 slave 可能有好幾個,
所以會有一個主要的 slave 去用 system("... %") 把其他的叫起來)
我曾經想過是不是沒有 flush() 的關係,
但是 flush() 的也沒用。
我也懷疑過是不是 fork() 導致導致兩個人搶同一個封包,
導致同步失敗,後來想一想根本不會,因為本來的程式碼用的是 system("... %")。
回頭再看看,問題真的很奇怪,
fp = fopen(...) ;
if (fp) {
fread() // 這邊竟然就死了
}
而且竟然只要等久一點,這邊就會過,
是不是我哪邊觀念有不對,或是忽略了什麼東西?
我想了兩天已經想破頭了,但是還是想不到原因。
有沒有人有類似的經驗,或是有任何建議,
任何建議都是受到歡迎的,因為我真的想不到啦 O_Q
如果我有哪邊描述的不夠清楚,也請告訴我。
謝謝。
我的 OS:
2.6.9-67.ELsmp
#1 SMP Wed Nov 7 13:56:44 EST 2007
x86_64 x86_64 x86_64 GNU/Linux
Compiler:
gcc version 3.4.6 20060404 (Red Hat 3.4.6-9)
PS.
大概有的人會問:你為什麼不把傳資料的部份改成用 socket?
1. 因為已經有很多既有的程式碼,傳送資料的部份太多了,
同步化的程式碼被封裝起來,只需要改很少地方。
2. 交換的資料量大約是 100~200 MB,
實際存取需要的時間大概是 1~2 秒,
但是整個程式的執行時間超過十分鐘,
所以修改這邊不符合效益。
--
To iterate is human, to recurse, divine.
遞迴只應天上有, 凡人該當用迴圈. L. Peter Deutsch
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 203.160.254.105
※ yoco315:轉錄至看板 LinuxDev 04/13 14:27
--
To iterate is human, to recurse, divine.
遞迴只應天上有, 凡人該當用迴圈. L. Peter Deutsch
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 203.160.254.105
1F:推 yauhh:讀或寫檔案過程前後做鎖和開鎖,你覺得如何? 61.231.67.175 04/13 15:23
2F:推 ji3g45j:用flag做同步...您是小學生嗎 124.8.112.217 04/14 00:09
3F:→ ji3g45j:Linux上2個process可用semaphor來做同步 124.8.112.217 04/14 00:09
4F:→ ji3g45j:可以用message queue、named pipe 124.8.112.217 04/14 00:09
5F:→ ji3g45j:socket來做資料傳輸,檔案很沒效率 124.8.112.217 04/14 00:10
6F:→ yauhh:..原來所謂flag控制流程是小學生作法 (筆記) 61.231.67.175 04/14 00:44
7F:→ yauhh:process之間的semaphor當然是變數,但你想: 61.231.67.175 04/14 00:49
8F:→ yauhh:二台電腦之間semaphore是什麼? 不是在共用 61.231.67.175 04/14 00:49
9F:→ yauhh:記憶體,就是在檔案裏,所以flag沒錯啊; 61.231.67.175 04/14 00:50
10F:→ yauhh:當然你用message queue維護共用變數也很好. 61.231.67.175 04/14 00:50
11F:推 pokkys:如果是透過NFS,試著用flock去測試看看.140.113.235.150 04/14 17:35
12F:推 pokkys:fclose可能沒有保護到nfs同步的問題140.113.235.150 04/14 17:37
13F:推 ji3g45j:如果你知道什麼叫做atomic、reentrant是 112.78.95.199 04/14 22:13
14F:→ ji3g45j:什麼 再來討論吧~~ 112.78.95.199 04/14 22:13
15F:→ yauhh:囂張勒,比人慢推文卻強調別人沒資格跟你討論 218.160.109.84 04/14 22:45
16F:→ yauhh:去去去,根本不希罕 218.160.109.84 04/14 22:45
17F:→ yauhh:我沒說非用flag不可,原po也沒說非用flag不可 218.160.109.84 04/14 22:46
18F:→ yauhh:卻因為flag被你嗆聲,好像你很了不起,滾開吧 218.160.109.84 04/14 22:47
19F:→ yauhh:在別人沒犯錯的情況下,你不必逼人選邊站,ok? 218.160.109.84 04/14 22:54
20F:→ yauhh:而且你懂reentrant也只不過是知道一個特定的 218.160.109.84 04/14 22:58
21F:→ yauhh:實作法,並且知道此法的名字而已. 218.160.109.84 04/14 22:58
22F:→ yauhh:需要做的時候,我也會查,然後學會怎麼實作. 218.160.109.84 04/14 22:59
23F:→ yauhh:抽象來講,也還不就是廣義的flag,那你還打壓 218.160.109.84 04/14 23:00
24F:→ yauhh:flag打壓得這麼爽. 你爽你自己的就好. 218.160.109.84 04/14 23:00
25F:→ yauhh:干我屁事. 218.160.109.84 04/14 23:00
26F:→ yauhh:而且我覺得你根本嗆錯重點了. 若我談到flag, 218.160.109.84 04/14 23:46
27F:→ yauhh:我所說的flag就包含在你提到的semaphore, 218.160.109.84 04/14 23:47
28F:→ yauhh:message queue, atomic,和reentrant中. 218.160.109.84 04/14 23:47
29F:→ yauhh:但你一定要說"不能用flag",就讓我很不能理解 218.160.109.84 04/14 23:48
30F:→ yauhh:你再會嗆,我根本不知道你嗆什麼和為什麼要嗆 218.160.109.84 04/14 23:49
31F:→ yauhh:這樣就不是溝通. 事實上,我也不必跟你溝通. 218.160.109.84 04/14 23:49
32F:→ yauhh:只想問,你也會像這樣嗆自己公司的同事嗎? 218.160.109.84 04/14 23:50
33F:→ yauhh:我覺得平白無故在網路上互相引起血氣,這不好 218.160.109.84 04/14 23:58
34F:推 ji3g45j:哇喔~~生氣了~好吧~~我跟你解釋一下 112.78.78.211 04/15 00:39
35F:→ ji3g45j:我覺得你應該不知道os能夠在任何時候切換 112.78.78.211 04/15 00:39
36F:→ ji3g45j:thread或process,就算是這樣的一個flag: 112.78.78.211 04/15 00:40
37F:→ ji3g45j:flag =1,OS也能夠在之中切換。我想你應該 112.78.78.211 04/15 00:40
38F:→ ji3g45j:知道race condition吧,那如果你設flag的 112.78.78.211 04/15 00:41
39F:→ ji3g45j:時候發生context switch的時候怎麼辦呢? 112.78.78.211 04/15 00:41
40F:→ ji3g45j:只有用semaphor或mutex才能阻止OS去存取 112.78.78.211 04/15 00:42
41F:→ ji3g45j:這樣...這位大大應該可以消氣了吧 112.78.78.211 04/15 00:42
42F:推 richardhesid:樓上根本就沒看清楚原po問什么122.233.166.114 04/15 00:55
43F:推 richardhesid:sem和mutex可以用來同步不同電腦上122.233.166.114 04/15 01:01
44F:→ richardhesid:的兩個prcess嗎?122.233.166.114 04/15 01:01