【问题标题】:Segmentation fault (core dumped) using stringstream in multithread application在多线程应用程序中使用字符串流进行分段错误(核心转储)
【发布时间】:2017-12-05 19:02:40
【问题描述】:

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

// 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 操作系统中构建,gcc 版本 5.4.0,编译标志:-std=c++17 -pthread -Wall

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

【问题讨论】:

  • 仅供参考文档注意localtime 可能不是线程安全的。如果您将呼叫移至锁内的generateString 会发生什么?
  • 分段错误不会突然出现。您是否检查了调试器中的堆栈跟踪,它究竟来自您的代码?
  • 检查您的向量?请记住,如果 vector 增长,它将完全重新分配其存储空间,因此线程可能指向垃圾。使用储备来预先确定向量的大小可能会有所帮助。
  • @RichardCritten 我试图将 generateString 移动到锁内。没有任何改变。
  • @user0042 是的,我检查了堆栈跟踪。调试器在 main() 函数中输入 LOG_MESSAGE。正确生成消息并落在 stringstream 析构函数上。

标签: c++ multithreading c++11 stringstream segmentation-fault


【解决方案1】:

问题解决了。 正如cmets中所说,threadVector.push_back(std::thread(test, std::ref(timerResult[i])));行不正确,因为timerResult中的内存重新分配是在调用push_back5次后完成的,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();
      ...
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-09
    • 2012-11-19
    • 2016-10-27
    • 2018-08-30
    • 1970-01-01
    • 2021-09-23
    • 2019-01-14
    • 1970-01-01
    相关资源
    最近更新 更多