2017-02-23 21 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”函数的线程发生同步问题。