2017-02-23 23 views
1

我在寫一個小程序,它爲主程序執行所有「寫入文件」工作。數據是結構不是恆定的大小。他們中有很多人,未來還會增加新的。 因爲這個原因,我決定使用char數組來處理指向這些數組的指針。在文件中寫入字符數組時遇到訪問衝突

代碼按預期運行的時間爲70%,但是當寫入數組時,我經常會遇到「訪問衝突」錯誤,並且有時會出現此錯誤連續發生的時間段。我只是找不到一個模式。

要注意的是執行運行在不同的線程上。

struct BufferElement 
{ 
    char* ptrData; 
    int TotalBytes; 
    int StartPosition; 
    std::string FileName; 
}; 

class FileThread 
{ 
private: 
    std::vector<BufferElement> Queue; 
    bool BoolThread; 
    std::ofstream writestream; 

//This Method calls the "WriteInFile" Method for the first element in the 
//Queue and erases it from the vector 
void Execute(void) 
{ 
    while(BoolThread) 
    { 
    if(Queue.size() > 0) 
    { 
     if(WriteInFile()) 
     { 
     delete[] Queue.at(0).ptrData; 
     Queue.erase(Queue.begin()); 
     } 
    } 
    } 
} 

//This Method writes the first Element of the Queue in the file 
bool WriteInFile(void) 
{ 
    if(Queue.at(0).ptrData == NULL) 
    { 
    return true; 
    } 

    writestream.open(Queue.at(0).FileName.c_str(), std::ios::in | 
         std::ios::out | std::ios::binary); 

    if(!writestream.is_open()) 
    { 
    writestream.close(); 
    writestream.clear(); 
    return false; 
    } 

    writestream.seekp(Queue.at(0).StartPosition); 
    writestream.write(Queue.at(0).ptrData, Queue.at(0).TotalBytes); 

    writestream.close(); 
    writestream.clear(); 

return true; 
} 

public: 
void EndThread(void) 
{ 
    BoolThread = false; 
    for(int i = 0; i < Queue.size(); i++) 
    { 
    delete[] Queue.at(i).ptrData; 
    } 
} 

template< typename T > 
void WriteOrder(std::string _FileName, T _Data, int _StartPosition) 
{ 
    BufferElement Temp_BufferElement; 
    Temp_BufferElement.TotalBytes = sizeof(_Data); 
    Temp_BufferElement.StartPosition = _StartPosition; 
    Temp_BufferElement.FileName = _FileName; 

    Temp_BufferElement.ptrData = new char[ Temp_BufferElement.TotalBytes ]; 
    memcpy(Temp_BufferElement.DataPtr, _Data, Temp_BufferElement.TotalBytes); 

    Queue.push_back(Temp_BufferElement); 
} 
}; 

int main(void) 
{ 
    std::string Path = "..\\Data\\Test.dat"; 
    FileThread Writer; 

    for(int i = 0; i < 1000; i++) 
    { 
    char array[] = {'H','e','l','l','o',' ','W','o','r','l','d','!','\0'}; 
    Writer.WriteOrder(Path, array, i * sizeof(array); 
    } 

    system("pause"); 
    Writer.EndThread(); 
    return 0; 
} 

我會很高興,如果有人可以看看代碼。也許我只是忽略了一些東西 我使用的是Borland Turbo C++ Builder,Thread是來自vcl類的對象。

+1

我假設'EndThread'被調用的線程不是'Execute'?我看不到任何同步。 – knivil

+0

是的。它從主線程中調用。同步是否必要?只有執行方法才能訪問文件 – Schmelix

+0

爲什麼不提供全線程創建和終止的代碼? – user

回答

2

您需要同步對隊列的訪問。如果您的主線程在工作線程修改它時寫入隊列,您可能會崩潰。此外,如果您執行push_back,則陣列內存可能無效,而工作人員仍在使用該無效內存。

我也看不到BoolThread在哪裏被初始化或更改。所以這個例子不完整,或者無論如何可能會表現奇怪。

+0

爲矢量添加了一些鎖守,現在它甚至可以在第100次迭代中起作用。謝謝 – Schmelix

+0

你也應該檢查'sizeof(Data)'問題,因爲這會導致其他副作用不能馬上通知。 – Devolus

0
void WriteOrder(std::string _FileName, T _Data, int _StartPosition) 
{ 
    BufferElement Temp_BufferElement; 
    Temp_BufferElement.TotalBytes = sizeof(_Data); 
    Temp_BufferElement.StartPosition = _StartPosition; 
    Temp_BufferElement.FileName = _FileName; 

    Temp_BufferElement.ptrData = new char[ Temp_BufferElement.TotalBytes ]; 
    memcpy(Temp_BufferElement.DataPtr, _Data, Temp_BufferElement.TotalBytes); 

    Queue.push_back(Temp_BufferElement); 
} 

如果被這樣:

Writer.WriteOrder(Path, array, i * sizeof(array)); 

Temp_BufferElement.TotalBytes將舉行4(或8)(的sizeof(_Data))貌似這個是不是你預期什麼。這條線:

Temp_BufferElement.ptrData = new char[ Temp_BufferElement.TotalBytes ]; 
     memcpy(Temp_BufferElement.DataPtr, _Data, Temp_BufferElement.TotalBytes); 

將分配在堆和拷貝4個字節(根據指針的大小,32/64位程序的)

此代碼:

Queue.push_back(Temp_BufferElement); 

此代碼之前是如果Queue.size()== Queue.capacity()被執行,向量將重新分配自己,從而導致執行「Execute」函數的線程發生同步問題。