作者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