文章标题 原创 翻译 转载 文章内容 线上出现了一个比较奇怪的问题,日期B的时间赋值给了日期A,但是浏览代码发现根本没有这样的逻辑。 经过一番调查基本能确定是localtime函数线程不安全造成的。 下面使用demo来模拟一下出现问题的情况 t1和t2是两个时间,使用GetTimeString转换的时候t2的时间可能会赋值给t1. test.cpp ``` #include <time.h> #include <iostream> #include <string> #include <vector> #include <boost/thread.hpp> #include <boost/shared_ptr.hpp> const time_t t1 = 1595486546; const time_t t2 = 2530972800; const std::string &T1 = "2020-07-23 14:42:26"; const std::string &T2 = "2050-03-16 00:00:00"; const int COUNT = 100000; std::string GetTimeString(time_t t) { if (t == -1) { return ""; } struct tm *local = localtime(&t); char timeChars[50]; strftime(timeChars, 50, "%Y-%m-%d %H:%M:%S", local); return std::string(timeChars); } void foo1() { for (int i = 0; i < COUNT; i++) { std::string str = GetTimeString(t1); if (str != T1) { std::cout << "foo1 ERROR i:" << i << " " << str << std::endl; break; } } } void foo2() { for (int i = 0; i < COUNT; i++) { std::string str = GetTimeString(t2); if (str != T2) { std::cout << "foo2 ERROR i:" << i << " " << str << std::endl; break; } } } int main() { std::cout << "t1:" << GetTimeString(t1) << std::endl; std::cout << "t2:" << GetTimeString(t2) << std::endl; std::cout << "-------------start-----------" << std::endl; std::vector<boost::shared_ptr<boost::thread> > threadList; for (int i = 0; i < 10; i++) { if (i % 2 != 0) { boost::shared_ptr<boost::thread> p(new boost::thread(foo1)); threadList.push_back(p); } else { boost::shared_ptr<boost::thread> p(new boost::thread(foo2)); threadList.push_back(p); } } for (int i = 0; i < threadList.size(); i++) { if (threadList[i]->joinable()) { threadList[i]->join(); } } std::cout << "exit" << std::endl; return 0; } ``` CMakeLists.txt ``` cmake_minimum_required(VERSION 2.8) project( process ) SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) find_package(Boost REQUIRED COMPONENTS thread ) if(NOT Boost_FOUND) message("Not found Boost") endif() include_directories(${Boost_INCLUDE_DIRS}) message("${Boost_INCLUDE_DIRS}") message("${Boost_LIBRARIES}") add_executable( process test.cpp ) target_link_libraries(process ${Boost_LIBRARIES}) ~ ``` 编译: ``` cmake . make ``` 运行: ``` ./process ``` 结果: ``` [root@node172 tujiaw]# ./process t1:2020-07-23 14:42:26 t2:2050-03-16 00:00:00 -------------start----------- foo2 ERROR i:25281 2050-03-16 00:00:26 foo2 ERROR i:25611 2050-03-16 06:42:26 foo1 ERROR i:18045 2050-03-16 00:00:00 foo2 ERROR i:41655 2050-03-23 14:42:26 foo2 ERROR i:25632 2050-03-16 06:42:26 foo1 ERROR i:84292 2020-07-23 06:42:26 exit ``` 以上是跑多次下来的结果,可以看到第一条foo1正确数据应该是t1,结果变成了2050年。 应该使用线程安全的localtime,如下代码在windows和linux下是线程安全的: ``` struct tm* LocalTimeSafe(time_t t, struct tm &local) { #ifdef WIN32 // 目前的版本windows是线程安全的 return localtime(&t); #else // linux下localtime_r是线程安全的, localtime线程不安全 return localtime_r(&t, &local); #endif } ``` 文章类别 Python Mobile Android Java Shell Life Database Bug Windows IOS Tools Boost Node.js Mac Product Tips C/C++ Golang Javascript React Qt MQ MongoDB Design Web Linux LLM ChatGPT RAG AI 提交