繁体   English   中英

在64位环境中读取32位缓存

[英]Read 32bit caches in 64bit environment

我们有很多建立在32位计算机上的缓存,现在必须在64位环境中读取。 当我们要打开读取缓存文件时,会遇到分段错误。

复制缓存将需要数周的时间,因此我想知道如何在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;
}

从该行:

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

我认为values指向long数组。 在除Widnows之外的大多数OS中, long 32位(32位构建)和64位(64位构建)都是long

您应该将文件读取为32位值(例如int32_t)的转储,然后将其复制尽可能长的时间。 并可能对文件进行版本控制,以便在读取时知道要应用的逻辑。

事实上,设计文件格式而不是仅使用内存转储可以防止此类问题(字节序,填充,FP格式...等其他可能出现的问题,因为您尝试的可移植性要比不只是编写文件的程序-尤其是填充可能会随编译器的发行版和编译标志而改变)。

您需要以这样的方式更改64位计算机上this->values的内存布局(无论是this->values类型,都没有提到关键信息),以使内存布局与32位计算机所使用的内存布局相同。

您可能需要使用诸如结构打包之类的编译器技巧或类似的方法来执行此操作,并且如果this->values恰好包含类,则编译器生成的内部类指针将很痛苦。

顺便说一句,C ++是否具有适当的显式大小的整数类型? #include <cstdint>吗?

使用long作为32bit数据类型是犯规的……至少在UN * X系统上不是这样,在64bit中不是这种情况(LP64数据模型, int是32bit,而long指针,是64bit)。

在Windows64(IL32P64数据模型, intlong 32bit,指针为64bit)上,您的代码以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)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM