作者yoco315 (眠月)
看板LinuxDev
标题Linux 上面读取档案发生超奇怪问题
时间Mon Apr 13 14:27:27 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
--
To iterate is human, to recurse, divine.
递回只应天上有, 凡人该当用回圈. L. Peter Deutsch
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 203.160.254.105