问个多线程写文件的问题,使用fwrite

youngwolf 2012-09-16 12:28:03
我对文件操作这一块一直鲜有涉及,还请有经验者指教,问题如下:

我在做一个文件传送系统,c/s结构。支持文件分块多线程下载,比如我有两个线程,文件总大小200K,则开始下载之前,每个线程用fopen(..., "w+b");得到FILE结构,是有序的,所以是线程1创建并打开文件,线程2(包括后面的线程,如果有的话)打开文件。

当开始数据传送之前,线程1 fseek到0的位置,线程2 fseek到100K的位置(两个seek已经在多线程中的,先后无法保证,甚至同时),之后,线程1和2完全异步的接收数据,并fwrite到FILE,每个线程收完数据之后调用fclose(也是完全异步的,在多线程之中),所有线程都结束之后,文件传送完成。

问题表现:
在win7 64bit下,隅尔会出现接收的文件内容不正确,但都是前面的内容不正确,就是线程1负责的部分,而且不正确的数据的数量也不确定,但总是最前面的不正确,比如线程1负责100K的数据,有时候是0-10K不对,有时候是0-20K不对。

在fedora 17 64bit下,从来没有出现过问题,ubuntu 12.04 LTS 64bit还没来得及试,试了我再补充上。

再也没有在其它环境下试过了。

请问我这个问题要怎样解决?
...全文
815 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
o桑相o 2015-05-22
  • 打赏
  • 举报
回复
肯定会出问题,假设有两个线程A和B,都要写文件,假设都有如下代码 n: fseek(file,pos,SEEK_SET); n+1 :fwrite(buffer,1,len,file); 出问题的情况: A线程执行到第n行的时候,即将执行n+1行代码之前,这时B线程也执行了第n行,这时指针的位置就发生了变化; A线程再执行n+1行时候写入的地方就变成了B线程fseek的位置 这是典型的多线程编程会出现的问题,通常的做法是,写文件由一个单独的线程来完成,其它线程将要写的内容包括位置等信息放入写入队列里面,由写文件的线程从队列里面取内容来写入,访问此队列时需要加锁
耿然 2014-03-04
  • 打赏
  • 举报
回复
感觉可能不是文件接收端的问题,是发送端的问题,fread那边。
傻X 2012-09-17
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]
能否确定两个线程打开文件的时间是在任一个线程写文件的时间之前?

可能是一个线程打开文件后写了20个字节的内容,然后另一个线程也打开了文件,你用的是wb+模式,文件内容全部被清空了。

这样就会出现文件开头N个字节都是为0x00的情况。
[/Quote]

有可能,楼主把open参数贴下看看
morebread 2012-09-17
  • 打赏
  • 举报
回复
能否确定两个线程打开文件的时间是在任一个线程写文件的时间之前?

可能是一个线程打开文件后写了20个字节的内容,然后另一个线程也打开了文件,你用的是wb+模式,文件内容全部被清空了。

这样就会出现文件开头N个字节都是为0x00的情况。
chayedanwc 2012-09-17
  • 打赏
  • 举报
回复
不同区块分别保存多个临时文件,完成后将多个临时文件拼为完整的文件。
youngwolf 2012-09-17
  • 打赏
  • 举报
回复
伪代码大概为:
for (分块数)
{
fopen
start a thread
}

在把第一个fopen改为w+b,后面的改为r+b的时候(上周日),我也觉得问题找到了。没想到还是不行,难道当时我在判断第一个的时候,手误写错了,比如0写成1之类,我会继续在win7上测试。
youngwolf 2012-09-17
  • 打赏
  • 举报
回复
参数的确有点问题,但改了问题还是有(也是随机成功,随机失败)。
我打开文件是顺序的(在一个线程里面打开所有文件,但接收数据和写文件就完全在不同的线程里面了),但的确是有可能第一个线程打开了文件,然后写了数据,第二个线程才打开文件,所以后来改为第一个用w+b,第二个用r+b,这样问题仍然没有得到解决。

后来报着试一试的态度,在fclose之前加了个fflush,奇迹般的没有问题了,这就更让我不放心了,但到目前为止,问题的确没有再次出现。msdn上说的很清楚,fclose会刷新缓存的。而且在linux下也不需要加fflush,只是在win7下才需要。
Eleven 2012-09-16
  • 打赏
  • 举报
回复
你所说的文件内容不正确指的是什么?改写的数据没有写完整还是什么的?
傻X 2012-09-16
  • 打赏
  • 举报
回复
大神,注意使用flush
miliggate 2012-09-16
  • 打赏
  • 举报
回复
这个貌似我也出现过,
解决方法是保存到一个队列里,然后再输出
hotpos 2012-09-16
  • 打赏
  • 举报
回复
一般0 表示这块数据没写.
youngwolf 2012-09-16
  • 打赏
  • 举报
回复
我是多线程用不同的文件符(FILE*)操作同一个文件,每个线程操作文件的不同块,不会交叉。
youngwolf 2012-09-16
  • 打赏
  • 举报
回复
回一楼,我有正常fclose的(它会自动flush的,平时我并没有马上强制flush的需求)。如果是因为多线程的问题,加个flush也不能解决问题,因为fwrite后面紧跟一个flush,并不能保证它们的原子性。

回二楼,谢谢你的提醒,我还真的少说了一点,出错的文件内容全是0。

奇怪之处有以下:
lunux下没事;
只有第一个线程(就是写文件最前面一块的线程)写的数据出错;
出错的数据总是0,不是随机;

注:
数据个数不出错,就是得到的结果的大小与原始文件完全一样,一字节不差。
fwrite之后,我以检测返回值的,也正确(写入个数据量等于fwrite中参数指定的量)。

16,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧