多线程对象中的堆损坏

时间:2014-08-14 15:21:53

标签: c++ multithreading c++03 heap-corruption

我试图构建一个包含循环缓冲区的单例类,每次某个函数想要转发发送内容到调试客户端(例如DBGview或类似函数)时,该函数会将其信息存储在循环缓冲区中。该对象还将运行一个将休眠一段时间的线程,然后唤醒并将缓冲区内容转储到调试客户端。

这是每个人在需要发送调试内容时调用的函数:

     TTFW_LogRet PrintToLogger (std::string Str)
     {
         Logger *Log;
         if(Instance_Mutex == NULL)
         {
              Instance_Mutex = CreateMutex(NULL,FALSE,NULL);
              if (Instance_Mutex == NULL) 
              {
                   OutputDebugStringA("CreateMutex error! the Logger will close \n");
                   return GENERAL_ERROR;
              }
          }
          Log = Logger::getLogInstance();
          Log->LogStringToOutput(Str);
          return SUCCESS;
       }

由于某种原因,我总是在返回SUCCESS语句

后收到堆损坏错误

这是Getinstance()函数:

Logger* Logger::getLogInstance()
{
    if(_instance == NULL)
    {
       MutexLock(Instance_Mutex);
       if(_instance == NULL)
       {
           _instance = new Logger();
       }
       MutexUnlock(Instance_Mutex);
   }
   return _instance;
  }

并且线程函数是:

    DWORD WINAPI Logger::WorkerThread (LPVOID lpParam )
    {
         Logger *log = static_cast <Logger*> (lpParam);

         for(;;)
         {

              Sleep(2000);
              if(log->getOutputMethod() == odBuffer && log->CyclicBuffer1.size() >= log->Thresh && !log->CyclicBuffer1.empty())
         {
                  TTFW_LogRet ret;
                  ret = log->FullBufferDump();
                  if (ret != SUCCESS)
                  {
                       log->LogStringToOutput("Error occured in dumping cyclic buffer , the buffer will be cleared\n");
                  }
            }
          }
         }

有没有人知道为什么这个代码会发生堆损坏?请注意,调试函数被多次调用,并且与转储缓冲区的线程没有同步。

2 个答案:

答案 0 :(得分:0)

您使用double checked locking会导致您看到的那种细微问题。特别是,C ++允许行

_instance = new Logger();

可能会导致_instanceLogger构造函数完成之前获得非NULL值。然后,如果另一个线程调用getLogInstance,则不满足条件if(_instance == NULL),并且线程将使用未完全初始化的对象。考虑使用直接锁定而不进行双重检查,或其他一些 - 可能依赖于实现 - 技术。在C ++ 11中,您可以安全地使用静态变量来实现此目的。

答案 1 :(得分:0)

我的通灵调试技巧告诉我LogStringToOutput不是线程安全的,并且在从多个线程调用时导致堆损坏。