【发布时间】: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