线上出现了一个比较奇怪的问题,日期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
}