在多线程应用程序中使用stringstream进行分段错误(核心转储)

时间:2017-12-05 19:02:40

标签: c++ multithreading c++11 stringstream sigsegv

我尝试做简单的线程安全记录器,它将消息打印到控制台。

// Test function for check logger. It is work
void test(double& diff)
{
  std::vector<double> result;
  for( int counter = 0; counter < 100000; ++counter)
  {
    result.push_back(clock());

    std::string text = "counter = ";
    text.append(std::to_string(counter));
    LOG_MESSAGE(text); //<-- Correct log..
  }
  diff = clock() - result.front();

}

int main(int argc, char** argv)
{
  double time2;
  double time1;
  std::vector<double> timerResult;
  std::vector<std::thread> threadVector;

  time1 = clock();
  for(int i = 0; i < 5; ++i) //<-- Create 5 thread of test function
  {
    timerResult.push_back(0);
    threadVector.push_back(std::thread(test, std::ref(timerResult[i])));
  }
  for(std::thread& t : threadVector)
    t.join();
  time2 = clock(); //<-- Threads is finished

  double res = 0;
  for(double tRes : timerResult)
     res += tRes;
  res = res / static_cast<double>(CLOCKS_PER_SEC);

  std::string message; //<-- Generate final message
  message.append("Timer: ")
      .append(std::to_string((time2 - time1) / (double)CLOCKS_PER_SEC))
      .append(" - thread timer: ")
      .append(std::to_string(res));

  LOG_MESSAGE(message); //<-- Crash inside!!    

  return 0;
}

Logger在线程中工作得很好。但是当我尝试登录在std :: ostringstream的析构函数中调用SIGSEGV信号的main()函数时(在构造日志消息的函数中):

static Logger::Core logger; //<--Global Logger variable

#define LOG_MESSAGE( TEXT ) logger.addNoteInLog(TEXT) //<-- Define for log message

void Core::addNoteInLog(const Message &message) //<-- threadsafe log function
{  
  std::string text;
  message.generateString(text); //<-- [Crash here] generate log message
  g_lock.lock();
  std::cout << text;
  g_lock.unlock();
}

void Message::generateString(std::string& text) const
{
  text.clear();
  tm *ltm = localtime(&mDate);

  std::ostringstream data; //<-- [Crash here] function is finished, but cannot destruct object.
  data << 1900 + ltm->tm_year << "/"
       << 1 + ltm->tm_mon << "/"
       << ltm->tm_mday << "\t";
  data << "[INF] - ";
  data << std::this_thread::get_id() << " - "
       << mMessage << "\n";

  text = data.str();
}

我不明白为什么线程中的记录器工作,但在main()函数崩溃。使用排除方法,我发现错误发生时:

  • 当我使用5个(或更多)线程时
  • 当测试功能不为空时
  • 当在generateString中使用stringstream或ostringstream或string.append()时(在最后一种情况下应用程序在同一个地方的std :: string析构函数中崩溃)

QtCreater中的say调试器。

在Ubuntu OS中构建,gcc版本5.4.0,编译标志:-std=c++17 -pthread -Wall

This是我的git存储库,有错误。

1 个答案:

答案 0 :(得分:0)

问题解决了。 正如评论中所述,行threadVector.push_back(std::thread(test, std::ref(timerResult[i])));不正确,因为timerResult中的内存重新分配是在调用push_back 5次后完成的,而ref(timerResult[i])传递引用是不正确的

正确的代码:

    int main(int argc, char** argv)
    {
      double time2;
      double time1;
      std::vector<double> timerResult (5); //<-- Create filling of vector
      std::vector<std::thread> threadVector;

      time1 = clock();
      for(int i = 0; i < 5; ++i)
      {
        //timerResult.push_back(0); //<-- incorrect filling of vector
        threadVector.push_back(std::thread(test, std::ref(timerResult[i])));
      }
      for(std::thread& t : threadVector)
        t.join();
      time2 = clock();
      ...
    }