【问题标题】:Access Violation when writing an char array in a file在文件中写入 char 数组时访问冲突
【发布时间】:2017-02-23 09:40:51
【问题描述】:

我正在编写一个小程序,它为主程序完成所有“写入文件”工作。数据是大小不固定的结构。它们有很多,将来会添加新的。 因此,我决定使用 char 数组并将指向这些数组的指针从一个方法传递到另一个方法。

代码有 70% 的时间按预期运行,但是在写入数组时我经常会遇到“访问冲突”错误,有时这个错误会连续出现几次。我只是找不到模式。

要注意的是,Execute 在不同的线程上运行。

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 类的对象。

【问题讨论】:

  • 我假设EndThread 在与Execute 不同的线程中被调用?而且我根本看不到同步。
  • 是的。它从主线程调用。是否需要同步?只有执行方法可以访问文件
  • 为什么不提供完整的线程创建和终止代码?

标签: c++ multithreading pointers ofstream


【解决方案1】:

您需要同步对队列的访问。如果您的主线程在工作线程正在修改队列时写入队列,您可能会崩溃。此外,如果您执行push_back,则数组内存可能会变得无效,而工作人员仍在使用该无效内存。

我也看不到 BoolThread 的初始化或更改位置。所以要么这个例子不完整,要么它可能表现得很奇怪。

【讨论】:

  • 为向量添加了一些锁保护,现在它甚至在第 100 次迭代中也能正常工作。谢谢
  • 您还应该检查sizeof(Data)issue,因为这会导致其他副作用不会立即引起注意。
【解决方案2】:
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(),则在执行此代码之前,向量将重新分配自身,从而导致执行“执行”函数的线程出现同步问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多