microseconds - usleep c++ linux
¿Por qué no hay una alternativa segura para hilos de C++ 11 a std:: localtime y std:: gmtime? (5)
En C ++ 11, todavía tiene que usar std::localtime
y std::gmtime
como indirección para imprimir un std::chrono::time_point
. Estas funciones no son seguras para usar en un entorno multiproceso como se introdujo con C ++ 11 porque devuelven un puntero a una estructura estática interna. Esto es especialmente molesto ya que C ++ 11 introdujo la conveniente función std::put_time
que casi no se puede usar por el mismo motivo.
¿Por qué esto es tan fundamental roto o me pasa algo?
Como otros mencionaron, realmente no hay conveniencia de hilos y formato de formato de tiempo portátil en cualquier estándar de C ++ disponible, pero hay alguna técnica de preprocesador arcaica que encontré utilizable (gracias a Andrei Alexandrescu en CppCon 2015 diapositivas 17 y 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
Aquí declaramos la función con el argumento de la plantilla size_t
y devolvemos el puntero al miembro estático std::tm
. Ahora cada llamada de esta función con argumento de plantilla diferente crea una nueva función con la nueva variable estática std::tm
. Si se define __COUNTER__
macro, se debe reemplazar por un valor entero incrementado cada vez que se usa, de lo contrario usaremos __LINE__
macro y en este caso mejor para asegurarnos de no llamar a macro utc
dos veces en una línea.
Global gmtime_call_mutex
protege la llamada std::gmtime
en cada std::gmtime
de instancias, y al menos en Linux no debería ser un problema de rendimiento ya que la adquisición de cerradura se realiza primero como spinlock, y en nuestro caso nunca debería terminar con un bloqueo de rosca real .
thread_local
asegura que diferentes hilos que ejecutan el mismo código con llamadas utc
seguirán funcionando con diferentes variables std::tm
.
Ejemplo de uso:
void work_with_range(
std::chrono::system_clock::time_point from = {}
, std::chrono::system_clock::time_point to = {}
)
{
std::cout << "Will work with range from "
<< ( from == decltype(from)()
? std::put_time( nullptr, "beginning" )
: std::put_time( utc( from ), "%Y-%m-%d %H:%M:%S" )
)
<< " to "
<< ( to == decltype(to)()
? std::put_time( nullptr, "end" )
: std::put_time( utc( to ), "%Y-%m-%d %H:%M:%S" )
)
<< "."
<< std::endl;
// ...
}
De acuerdo con N2661 , el documento que agregó <chrono>
:
Este documento no ofrece servicios calendáricos a excepción de un mapeo mínimo desde y hacia
time_t
de C.Como este documento no propone una biblioteca de fecha / hora, ni especifica épocas, tampoco aborda los segundos intercalares. Sin embargo, una biblioteca de fecha / hora encontrará que esta es una excelente base sobre la cual construir.
Este documento no propone una biblioteca de cantidades físicas de propósito general.
Este documento propone una base sólida que, en el futuro, podría proporcionar un punto de partida compatible para una biblioteca de unidades físicas generales. Si bien dicha biblioteca futura podría tomar cualquiera de varias formas, la presente propuesta se detiene antes de ser realmente una biblioteca de unidades físicas. Esta propuesta es específica del tiempo y sigue estando motivada por las necesidades relacionadas con el tiempo de la biblioteca de subprocesos.
El objetivo principal de esta propuesta es satisfacer las necesidades de la API estándar de subprocesamiento de bibliotecas de una manera que sea fácil de usar, segura de usar, eficiente y lo suficientemente flexible como para no quedar obsoleta 10 o incluso 100 años a partir de ahora. Cada característica contenida en esta propuesta está aquí por una razón específica con casos de uso práctico como motivación. Las cosas que cayeron en la categoría de "cool", o "que suena como que podrían ser útiles", o "muy útiles pero no necesarias para esta interfaz" no se han incluido. Dichos artículos pueden aparecer en otras propuestas, y posiblemente se dirijan a un TR.
Tenga en cuenta que el objetivo principal de <chrono>
es "satisfacer las necesidades de la API de threading de biblioteca estándar", que no requiere servicios de calendario.
No existe una alternativa segura para hilos a std::localtime
y std::gmtime
porque no propones una y la clasificas a lo largo de todo el proceso de estandarización. Y tampoco lo hizo nadie más.
El único código de calendario de chrono
es un código que ajusta las funciones time_t
existentes. Estandarizar o escribir nuevos estaba fuera del dominio del proyecto de chrono
. Hacer tal estandarización requeriría más tiempo, más esfuerzo y agregará más dependencias. Simplemente envolviendo cada función time_t
era simple, tenía pocas dependencias y era rápido.
Concentraron su esfuerzo por poco. Y tuvieron éxito en lo que se enfocaron.
Te animo a que comiences a trabajar en <calendar>
o te unas a tal esfuerzo para crear una sólida API de calendario para std
. Buena suerte y buena suerte!
Si está dispuesto a utilizar una biblioteca de terceros de fuente abierta gratuita, aquí hay una forma de imprimir std::chrono::system_clock::time_point
en UTC:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << system_clock::now() << " UTC/n";
}
Esta es una alternativa segura para subprocesos a std::gmtime
utilizando la sintaxis moderna de C ++.
Para una sustitución std::localtime
moderna y segura para subprocesos, necesita esta biblioteca de zona horaria de nivel superior estrechamente relacionada y la sintaxis se ve así:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << make_zoned(current_zone(), system_clock::now()) << "/n";
}
Ambos saldrán con la precisión que soporte su system_clock
, por ejemplo:
2016-07-05 10:03:01.608080 EDT
(microsegundos en macOS)
Estas bibliotecas van mucho más allá de un reemplazo de gmtime
y gmtime
. Por ejemplo, ¿quieres ver la fecha actual en el calendario juliano?
#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
¿Qué hay de la hora actual de 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
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0355r0.html
gmtime
y gmtime
tienen un almacenamiento interno que es estático, lo que significa que no son seguros (tenemos que devolver un puntero a una estructura de datos, por lo que debe asignarse dinámicamente, un valor estático o un valor global, ya que la asignación dinámica memoria, esa no es una solución razonable, lo que significa que tiene que ser una variable global o estática [teóricamente, se podría asignar y almacenar en TLS, y hacerlo seguro para hilos de esa manera]).
La mayoría de los sistemas tienen alternativas seguras para hilos, pero no son parte de la biblioteca estándar. Por ejemplo, Linux / Posix tiene gmtime_r
y gmtime_r
, que toma un parámetro adicional para el resultado. Ver por ejemplo http://pubs.opengroup.org/onlinepubs/7908799/xsh/gmtime.html
Del mismo modo, las bibliotecas de Microsoft tienen gmtime_s
, que también es reentrante y funciona de manera similar (pasando el parámetro de salida como una entrada). Ver http://msdn.microsoft.com/en-us/library/3stkd9be.aspx
¿En cuanto a por qué la biblioteca estándar de C ++ 11 no utiliza estas funciones? Tendría que preguntarle a la gente que escribió esa especificación: espero que sea portátil y conveniente, pero no estoy del todo seguro.