在C ++ 11中,您仍然必须使用std::localtime
和std::gmtime
作为间接打印std::chrono::time_point
。这些函数在C ++ 11引入的多线程环境中使用是不安全的,因为它们返回一个指向内部静态结构的指针。这尤其令人讨厌,因为C ++ 11引入了方便的函数std::put_time
,由于同样的原因,该函数几乎无法使用。
为什么这么根本被打破或者我忽略了什么?
答案 0 :(得分:17)
根据N2661,添加<chrono>
的论文:
除了最小限度之外,本文不提供日历服务 映射到C&#39 {s}
time_t
。由于本文未提出日期/时间库,也没有指定时期,因此它也没有解决闰秒问题。但是,日期/时间 图书馆会发现这是一个很好的基础 建立。
本文未提出通用物理量 库。
本文提出了一个坚实的基础,在未来,可以为一般的物理单位提供兼容的起点 图书馆。虽然这样的未来图书馆可能采取多种形式, 目前的提案远远没有实际存在 单位图书馆。该提案是具体时间的,并且将继续如此 由线程库的时间相关需求驱动。
该提案的主要目标是满足人们的需求 标准库线程API,易于使用,安全 使用,高效,灵活,足以不被淘汰10甚至 100年后的今天。此提案中包含的每个功能都在此处 出于特定原因,以实际使用案例为动机。事情 它属于&#34;酷&#34;或者#34;这听起来像它可能 是有用的&#34;,或&#34;非常有用,但不需要此接口&#34;没有 被包括在内。这些项目可能出现在其他提案中,并且 可能针对TR。
请注意,<chrono>
的主要目标是满足标准库线程API&#34;的需求,它不需要日历服务。
答案 1 :(得分:11)
localtime
和gmtime
具有静态的内部存储,这意味着它们不是线程安全的(我们必须返回指向数据结构的指针,因此它必须动态分配,静态值或全局值 - 因为动态分配会泄漏内存,这不是一个合理的解决方案,这意味着它必须是全局变量或静态变量[理论上,可以在TLS中分配和存储,并使其成为线程安全的方式]) 。
大多数系统都有线程安全的替代品,但它们不是标准库的一部分。例如,Linux / Posix有localtime_r
和gmtime_r
,它为结果提供了额外的参数。例如,参见
http://pubs.opengroup.org/onlinepubs/7908799/xsh/gmtime.html
类似地,Microsoft库具有gmtime_s
,它也是可重入的并且以类似的方式工作(将输出参数作为输入传递)。见http://msdn.microsoft.com/en-us/library/3stkd9be.aspx
至于为什么标准C ++ 11库没有使用这些功能?你不得不问那些编写该规范的人 - 我希望它具有便携性和便利性,但我并不完全确定。
答案 2 :(得分:7)
std::localtime
和std::gmtime
没有线程安全替代方法,因为您没有提出并在整个标准化过程中编组它。其他人都没有。
chrono
唯一的日历代码是包含现有time_t
函数的代码。标准化或编写新的项目超出了chrono
项目的范围。执行此类标准化需要更多时间,更多工作,并添加更多依赖项。简单地包装每个time_t
函数很简单,依赖性很少,而且很快。
他们的工作范围很窄。他们成功地关注了他们所关注的事情。
我建议您开始使用<calendar>
或加入此类工作,为std
创建强大的日历API。祝你好运,加快速度!
答案 3 :(得分:3)
如果您愿意使用free, open-source 3rd party library,以下是以UTC格式打印std::chrono::system_clock::time_point
的方法:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << system_clock::now() << " UTC\n";
}
这是std::gmtime
使用现代C ++语法的线程安全替代方法。
对于现代的,线程安全的std::localtime
替换,您需要这个密切相关的higher level timezone library,语法如下所示:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << make_zoned(current_zone(), system_clock::now()) << "\n";
}
这两个输出都会以system_clock
支持的精度输出,例如:
2016-07-05 10:03:01.608080 EDT
(macOS上的微秒)
这些库远远超出了gmtime
和localtime
替代品。例如,您想要查看Julian日历中的当前日期吗?
#include "julian.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << julian::year_month_day(date::floor<date::days>(system_clock::now())) << "\n";
}
2016-06-22
目前的GPS时间怎么样?
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
std::cout << std::chrono::system_clock::now() << " UTC\n";
std::cout << gps_clock::now() << " GPS\n";
}
2016-07-05 14:13:02.138091 UTC
2016-07-05 14:13:19.138524 GPS
https://github.com/HowardHinnant/date
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0355r0.html
<强>更新强>
“date.h”和“tz.h”库现在在C ++ 2a规范草案中,只有很小的改动,我们希望'a'为'0'。它们将位于标题<chrono>
和namespace std::chrono
下方(并且不会有date namespace
)。
答案 4 :(得分:2)
正如其他人所提到的,在任何可用的C ++标准中都没有线程安全便利和便携式时间格式化方法,但我发现有一些古老的预处理器技术可用(感谢Andrei Alexandrescu在CppCon 2015幻灯片17&amp; 18):
std::mutex gmtime_call_mutex;
template< size_t For_Separating_Instantiations >
std::tm const * utc_impl( std::chrono::system_clock::time_point const & tp )
{
thread_local static std::tm tm = {};
std::time_t const time = std::chrono::system_clock::to_time_t( tp );
{
std::unique_lock< std::mutex > ul( gmtime_call_mutex );
tm = *std::gmtime( &time );
}
return &tm;
}
#ifdef __COUNTER__
#define utc( arg ) utc_impl<__COUNTER__>( (arg) )
#else
#define utc( arg ) utc_impl<__LINE__>( (arg) )
#endif
这里我们用size_t
模板参数声明函数并返回指向静态成员std::tm
的指针。现在,使用不同模板参数对此函数进行的每次调用都会创建一个带有全新静态std::tm
变量的新函数。如果定义了__COUNTER__
宏,则每次使用时都应该用增量整数值替换它,否则我们使用__LINE__
宏,在这种情况下更好地确保我们不调用宏{{1在一行中两次。
全局utc
保护每个实例化中的非线程安全gmtime_call_mutex
调用,至少在Linux中不应该是性能问题,因为锁获取首先执行为在spinlock中运行,在我们的例子中永远不应该以真正的线程锁定结束。
std::gmtime
确保使用thread_local
调用运行相同代码的不同线程仍可使用不同的utc
变量。
使用示例:
std::tm
答案 5 :(得分:0)
Boost:不完全确定这是否是线程安全的,但似乎是这样:
#include "boost/date_time/posix_time/posix_time.hpp"
std::wstring stamp = boost::posix_time::to_iso_wstring(
boost::posix_time::second_clock::local_time());
std::wstring stamp = boost::posix_time::to_iso_wstring(
boost::posix_time::second_clock::universal_time());
见https://www.boost.org/doc/libs/1_75_0/doc/html/date_time/examples.html