**问题的上下文:**我有一个包含具有唯一结构的数据的大型二进制文件。这种数据的一个单元称为“事件”。每个事件有32016字节,一个文件包括大约400000个事件,使文件~12 GB。我正在编写一个程序来处理这些事件,并尝试使用多线程方法,让多个线程阅读文件的不同部分(让每个线程使用自己的文件流)。
问题是fseek无法找到文件的正确位置。以下是最小可再现的示例。该程序读取一个二进制文件与473797事件计划使用20胎面,而每个胎面使用不同的文件流。
#include <iostream>
#include <stream>
#include <errno.h>
#include <string.h>
using namespace std;
int main(){
FILE *segment[20];
int ret=0;
int eventsPerThread=473797/20;
int eventSize=8004;
for(int k=0;k<20;++k){
segment[k]=fopen("Datafile_367.bin","rb");
if(segment[k]==NULL){
std::cout<<"file stream is NULL!"<<k<<"\n";
}
ret=fseek(segment[k],eventsPerThread*eventSize*4*k,SEEK_SET);
std::cout<<ret<<":::"<<strerror(errno)<<"\n";
}
return 0;
}
以下是输出。fseek有时成功,返回0,而在其他时候失败,错误代码为22(无效参数)。
0:::Success
0:::Success
0:::Success
-1:::Invalid argument
-1:::Invalid argument
-1:::Invalid argument
0:::Invalid argument
0:::Invalid argument
0:::Invalid argument
-1:::Invalid argument
-1:::Invalid argument
-1:::Invalid argument
0:::Invalid argument
0:::Invalid argument
0:::Invalid argument
-1:::Invalid argument
-1:::Invalid argument
0:::Invalid argument
0:::Invalid argument
0:::Invalid argument
对fseek()函数的这种行为有什么解释吗?
(Note最小的可重复例子是单个胎面。一旦程序开始读取事件,就会发生多线程)
1条答案
按热度按时间oyjwcjzk1#
错误是偏移计算中的溢出。您使用
int
,它显然是4个字节宽。INT_MAX
是2147483647这个宽度。让我们看看:
| K|
eventsPerThread * eventSize * 4 * k
|溢出int
|返回值fseek()
|| --|--|--|--|
| 0 | 0 | 0 | 0 |
| 1 | 758427024 | 758427024 | 0 |
| 2 | 1516854048 | 1516854048 | 0 |
| 3 | 2275281072 |2019686224|-1个|
| 4 | 3033708096 |电话:1261259200|-1个|
| 5 | 3792135120 |粤ICP备0502832176号|-1个|
| 6 | 4550562144 | 255594848 | 0 |
| 7 | 5308989168 | 1014021872 | 0 |
| :|:|:|:|
由于溢出,结果
int
变为负值,fseek()
对此不满意。首先,确保
long
的宽度大于4个字节。然后将乘法的至少一个操作数更改为long
。例如,eventsPerThread * eventSize * 4L * k
。