2011-03-11 103 views
0

我们有许多高速缓存建立在32位机器上,我们现在必须在64位环境中读取这些高速缓存。 当我们想要打开读取缓存文件时,会出现分段错误。在64位环境中读取32位高速缓存

这将需要几个星期来重现缓存,所以我想知道如何仍然可以在64位机器上处理我们的32位缓存文件。

下面是我们用来读取和写入我们的缓存代码:

bool IntArray::fload(const char* fname, long offset, long _size){ 
    long size = _size * sizeof(long); 

    long fd = open(fname, O_RDONLY); 
    if (fd >0 ){ 
    struct stat file_status; 
    if (stat(fname, &file_status) == 0){ 
     if (offset < 0 || offset > file_status.st_size){ 
     std::__throw_out_of_range("offset out of range"); 
     return false; 
     } 
     if (size + offset > file_status.st_size){ 
     std::__throw_out_of_range("read size out of range"); 
     return false; 
     } 

     void *map = mmap(NULL, file_status.st_size, PROT_READ, MAP_SHARED, fd, offset); 
     if (map == MAP_FAILED) { 
     close(fd); 
     std::__throw_runtime_error("Error mmapping the file"); 
     return false; 
     } 

     this->resize(_size); 
     memcpy(this->values, map, size); 

     if (munmap(map, file_status.st_size) == -1) { 
     close(fd); 
     std::__throw_runtime_error("Error un-mmapping the file"); 
     return false; 
     /* Decide here whether to close(fd) and exit() or not. Depends... */ 
     } 

     close(fd); 
     return true; 
    } 
    } 
    return false; 
} 
bool IntArray::fsave(const char* fname){ 
    long fd = open(fname, O_WRONLY | O_CREAT, 0644); //O_TRUNC 
    if (fd >0 ){ 
    long size = this->_size * sizeof(long); 
    long r = write(fd,this->values,size); 
    close(fd); 

    if (r != size){ 
     std::__throw_runtime_error("Error writing the file"); 
    } 
    return true; 
    } 
    return false; 
} 
+1

这些缓存包含什么? – DarkDust 2011-03-11 08:37:17

+1

如果您提供了正在读取的实际数据类型以及您正在处理的平台,那将会很有趣。在大约64个平台中,“long”是32位,而在其他平台中则是64位,这可以解释这个问题。作为一个方面说明,你不应该直接调用以'__'开头的方法,因为这些方法是为实现保留的,并且可以随时更改。如果你想抛出一个'std :: runtime_error',就这样做:'throw std :: runtime_error(“my_error”)' – 2011-03-11 09:56:22

回答

3

从行:

long size = this->_size * sizeof(long); 

我假定values指向的long阵列。在绝大多数操作系统例外的Widnows中,long是32位构建的32位和64位构建的64位。

您应该将文件作为32位值的转储(例如int32_t)读取,然后将其复制为长。并且可能会对您的文件进行版本化,以便您在阅读时了解应用哪种逻辑。事实上,设计一个文件格式而不是仅仅使用内存转储就可以避免这种问题(字节序,填充,FP格式,...是其他会出现的问题是你试着稍微宽一些可移植性不仅仅是写入文件的程序 - padding尤其可能随编译器发布和编译标志而改变)。

+0

或者只是改变代码以显式地使用'int32_t'作为'values',并且确保编译器在没有填充的情况下密集地包装这些'int32_t'。这应该适用于32位和64位机器上的旧文件。那么,如何在C++中移植一个'int32_t'类型的问题仍然存在,因为AFAIR只是C语言,它在一个标准中定义了'stdint.h',C++仍然需要赶上。 – ndim 2011-03-11 08:51:15

+0

例外,如果使用64位的原因是容量较大,并暗示'int32_t'现在不能保存值。 (在unix下,POSIX需要'',所以它非常便携。) – AProgrammer 2011-03-11 08:55:11

+0

谢谢,我们现在使用你的答案修改为int32_t。 – eddy147 2011-03-11 20:36:38

1

您需要更改的this->values内存布局(无论何种类型,可能是,你是不是提的是,关键的信息)的64位机器的内存布局与32位机器使用的内存布局相同。

您可能需要使用编译器技巧(如结构打包或类似的东西来做到这一点),并且如果this->values碰巧包含类,那么编译器生成的内部类指针会很麻烦。

顺便说一句,C++有合适的明确大小的整数类型吗? #include <cstdint>

0

你堕落使用long为32位数据类型......这是,犯规至少在UN * X系统,而不是在64位的情况下(LP64数据模型,int是32位,但long和指针是64位)。

在Windows64(IL32P64数据模型,intlong 32位,但三分球64)你的代码的sizeof(long)直接从做映射文件memcpy()的对象化的阵列单元进行大小计算实际上将继续工作......

在UN * X上,这意味着在迁移到64位时,为了保持代码的可移植性,切换到明确大小的int32_t(从<stdint.h>)以确保您的数据结构布局保持不变同时执行32位和64位目标编译。

如果您坚持保留long,那么您必须将数组的内部化/外部化从简单的memcpy()/write()更改为以不同方式做事。SANS错误处理(你必须已经上图),它会看起来像这样的::fsave()方法,而是采用write()你做到:

long *array = this->values; 
int32_t *filebase = 
    mmap(NULL, file_status.st_size, PROT_WRITE, MAP_SHARED, fd, offset); 

for (int i = 0; i < this->_size; i++) { 
    if (array[i] > INT32_MAX || array[i] < INT32_MIN) 
     throw (std::bad_cast); // can't do ... 
    filebase[i] = static_cast<int32_t>(array[i]); 
} 

munmap(filebase, file_status.st_size); 

,为::fload()你会做以下代替memcpy()

long *array = this->values; 
int32_t *filebase = 
    mmap(NULL, file_status.st_size, PROT_READ MAP_SHARED, fd, offset); 

for (int i = 0; i < this->_size; i++) 
    array[i] = filebase[i]; 

munmap(filebase, file_status.st_size); 

注:前面已经已经提到,这种方法会如果你有什么比简单数组更复杂,不能因为除了数据类型大小的差异可能有不同的对齐限制和不同的填充规则。似乎不是你的情况,因此只有在考虑扩展这种机制时才记住(不要 - 使用像boost :: any或Qt :: Variant这样的可以外部化/内部化的测试库)。