2011-03-11 97 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這樣的可以外部化/內部化的測試庫)。