百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

c/c++获取linux系统时间的函数哪些是线程安全的?

ahcoder 2025-02-04 12:34 13 浏览

c/c++获取linux系统时间的函数有多种,但是在多线程编程时,我们需要知道他们的实现原理,从而判断是否是线程安全的。

time函数

  • 函数原型:
time_t time(time_t *tloc);
  • 它返回从 1970 年 1 月 1 日 00:00:00 UTC到当前时间的秒数。如果tloc不是NULL,则返回值也会存储在tloc指向的位置。
  • 线程安全分析:time函数本身是线程安全的。因为它主要是获取一个系统时间的整数值(time_t类型),没有涉及到共享的静态数据结构等可能导致数据竞争的情况。
  • 安全问题分析:通常情况下比较安全,但如果在使用time函数返回的time_t值时,没有正确地进行范围检查或者在传递给其他函数时没有考虑数据类型兼容性等问题,可能会导致程序错误。例如,将time_t值错误地解释为其他类型进行计算。
  • 内部实现原理:time函数在 Linux 系统中通常是通过系统调用(如gettimeofday系统调用的部分功能)来获取系统的时间戳。系统内部维护着一个高精度的时间计数器,time函数读取这个计数器的值并将其转换为从 1970 年 1 月 1 日 00:00:00 UTC 开始计算的秒数。

localtime和localtime_r函数

  • 函数原型:
struct tm* localtime(const time_t* timep);
struct tm* localtime_r(const time_t* timep, struct tm* result);

localtime函数将time_t类型的时间值转换为本地时间的struct tm结构,localtime_r是可重入版本

  • 线程安全分析:
    • localtime函数不是线程安全的。因为它使用一个静态的struct tm结构来存储转换后的时间,在多线程环境下可能会导致数据竞争。
    • localtime_r函数是线程安全的。它允许调用者提供一个struct tm结构来存储结果,避免了多个线程对共享数据的竞争。
  • 安全问题分析:
    • 对于localtime函数,如前面所述,在多线程环境中使用可能会导致数据错误。并且如果对localtime返回的struct tm结构指针进行非法访问(如超出结构范围访问),可能会导致缓冲区溢出等问题。
    • localtime_r函数在正确使用(提供合法的struct tm结构指针)的情况下相对安全,但如果提供的struct tm结构没有足够的内存空间或者被其他线程非法修改,也可能会出现问题。
  • 内部实现原理:

这些函数主要是根据系统的时间设置(包括时区等信息)来计算time_t值对应的年、月、日、时、分、秒等信息。对于localtime,内部使用静态struct tm结构存储结果,在计算过程中会填充这个结构。而localtime_r则是按照调用者提供的struct tm结构来填充结果,计算过程涉及到对时间戳进行数学运算,如先计算总天数来确定年份,再根据年份计算月份等,同时会考虑闰年等因素。


gmtime和gmtime_r函数

  • 函数原型:
struct tm* gmtime(const time_t* timep);
struct tm* gmtime_r(const time_t* timep, struct tm* result);

它们的功能类似于localtimelocaltime_r,但是gmtime函数是将time_t类型的时间值转换为格林威治标准时间(GMT)的struct tm结构,gmtime_r是可重入版本。

  • 线程安全分析:

gmtime函数不是线程安全的,原因和localtime类似,它使用静态struct tm结构。

gmtime_r函数是线程安全的,通过让调用者提供struct tm结构来存储结果避免数据竞争。

  • 安全问题分析:

对于gmtime函数,同样存在多线程数据竞争和非法访问struct tm结构导致的问题。

gmtime_r函数在正确使用时比较安全,但也要注意提供的struct tm结构的合法性。

  • 内部实现原理:

计算原理和localtime类似,不过是基于格林威治标准时间来计算。在计算过程中,不考虑本地时区和夏令时等因素,直接根据从 1970 年 1 月 1 日 00:00:00 UTC 开始的时间戳来确定年、月、日等信息,将这些信息填充到struct tm结构中。

gettimeofday函数

  • 函数原型:
int gettimeofday(struct timeval *tv, struct timezone *tz);

它返回当前日期和时间,tv参数用于存储秒数和微秒数,tz参数用于存储时区信息(在现代应用中通常设置为NULL,因为时区信息可以通过其他方式获取)。

  • 线程安全分析:

gettimeofday函数本身是线程安全的。它主要是获取系统的时间值和微秒值,没有涉及到共享数据结构导致的数据竞争。

  • 安全问题分析:

如果对struct timeval结构(包含秒数和微秒数)的使用不当,比如没有正确处理其成员变量或者在传递过程中修改了不该修改的部分,可能会导致程序错误。另外,在一些特殊情况下,如系统时间被恶意修改或者系统时钟出现异常,获取的时间数据可能不准确。

  • 内部实现原理:

在 Linux 内核中,系统维护着高精度的时钟硬件设备(如高精度定时器)。gettimeofday函数通过系统调用机制访问内核中的时间管理模块,读取当前时间的秒数和微秒数,然后将这些值填充到struct timeval结构中。它还可以根据系统的配置读取时区信息填充到struct timezone结构中,但通常在实际应用中不使用这个功能。


clock_gettime函数

  • clock_gettime函数的原型:
#include <time.h>
 int clock_gettime(clockid_t clk_id, struct timespec *tp);

其中:

  • clk_id参数用于指定要获取时间的时钟类型,常见的取值有以下几种123:
    • CLOCK_REALTIME:表示系统的真实时间,会随着系统时间的调整而改变,从 UTC 1970-1-1 00:00:00 开始计时 。
    • CLOCK_MONOTONIC:表示系统的运行时间,从系统启动这一刻起开始计时,不受系统时间被用户改变的影响,即单调递增的时间。
    • CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统 CPU 花费的时间。
    • CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统 CPU 花费的时间。
  • tp参数是一个指向struct timespec结构体的指针,用于存储获取到的时间信息,struct timespec结构体的定义如下:
struct timespec
 { 
time_t tv_sec; /* 秒 */
 long tv_nsec; /* 纳秒 */
 };

该函数的返回值为 0 表示成功,返回 - 1 表示失败,失败时会设置errno来指示错误原因,常见的错误码有:

  • EFAULT:tp指向的地址空间不可访问。
  • EINVAL:clk_id无效或不被支持。
  • ENOTSUP:系统不支持该时钟类型。
  1. 线程安全性分析
  • 结论:clock_gettime函数是线程安全的
  • 安全问题分析:
    • 该函数不会因为多个线程同时调用而出现数据竞争的情况。这是因为它在获取时间时,不会共享内部可能被修改的全局状态(如在localtime函数中存在的共享静态struct tm结构的问题)。每个线程调用clock_gettime获取的时间信息是独立的,不受其他线程的影响。
    • 然而,在使用clock_gettime函数返回的结果(struct timespec结构)时,如果多个线程同时访问和修改这个结构,可能会导致数据不一致。但这属于对返回结果的不当使用,而非函数本身的问题。例如,如果一个线程正在读取struct timespec结构中的时间值用于计算,而另一个线程同时修改了这个结构,就可能出现计算错误。
  1. 函数内部实现原理
  • 时钟源访问:在 Linux 系统中,clock_gettime函数是通过系统调用实现的。系统维护了多个不同的时钟源,clock_gettime函数根据传入的clockid_t参数(时钟 ID)来选择访问不同的时钟。例如,CLOCK_REALTIME是系统实时时钟,它可以获取当前系统时间,并且可以通过系统设置来改变;CLOCK_MONOTONIC是单调时钟,从系统启动开始单调递增,不受系统时间调整(如用户手动修改时间)的影响。
  • 时间读取机制:
    • 当clock_gettime函数被调用时,它通过内核提供的接口访问相应的时钟硬件设备(如高精度定时器)或者内核维护的时间计数器。对于高精度时钟,例如,内核可能会使用硬件定时器产生的高频中断来更新时间计数器。这些计数器的值经过一定的转换和处理后,被填充到struct timespec结构中返回给用户空间程序。struct timespec结构包含两个成员,tv_sec(秒数)和tv_nsec(纳秒数),以提供高精度的时间信息。
    • 以CLOCK_REALTIME为例,内核会将当前系统时间(包括从硬件时钟获取的时间,并考虑时区等因素)转换为秒数和纳秒数,填充到struct timespec结构。对于CLOCK_MONOTONIC,内核会根据系统启动后的时间计数(如基于 CPU 的时间戳计数器等)来生成秒数和纳秒数,确保时间是单调递增的。

相关推荐

KaOS 2025.05版本发布:全面拥抱Qt6,彻底告别Qt5

KaOSLinux2025.05版本重磅发布:全面拥抱Qt6,开启KDE生态新篇章继2025.03版本发布两个月后,专注于KDE桌面环境、采用XFS文件系统的滚动发行版Li...

基于FIMC接口的CMOS摄像头驱动分析与设计

摘要:目前的嵌入式系统中,USB摄像头使用比较普遍,但其应用会受到传输速度的限制。本文采用一款高速CMOS摄像头,其驱动利用S3C6410内置的FIMC接口技术,采用DMA和ping-pong缓冲...

没错是微软 推出基于Linux的交换机系统

2015-09-2205:59:59作者:郑伟你没看错,为了提升自身Azure云数据中心内网络设备的兼容性及开放性,微软也开始推出基于Linux的网络交换机系统了。这个被称为AzureCloud...

Linus Torvalds 宣布首个 Linux 内核 6.16 候选版本

Linux内核负责人兼创始人LinusTorvalds宣布关闭合并窗口,该窗口用于将主要新功能添加到内核中,并开始发布Linux6.16候选版本,从候选版本1(Linux6.16-r...

Linux内核漏洞将影响Haswell架构服务器

在infoq网站上,GilTene最近报告一个十分重要,但并不为人知Linux内核补丁,特别对采用Haswell架构的Linux系统用户和管理员应该特别关注。报告提醒RedHat发行版的用户(包括...

关于Linux性能调优中网络I/O的一些笔记

写在前面和小伙伴分享一些Linux网络优化的笔记,内容很浅,可以用作入门博文内容结合《Linux性能优化》读书笔记整理涉及内容包括常用的优化工具(mii-tool,ethtool,ifconfig,i...

国产操作系统- Veket Linux(国产操作系统之光银河麒麟阅读理解)

VeketLinux是一个随身的可装在U盘的Linux操作系统。主要面向桌面用户。它的设计重点是提供简单易用且稳定的操作系统,同时保持更新和开发。它具有强大的功能集和广泛的用户基础,可满足...

AlmaLinux 9.6发布:升级工具、初步支持IBM Power虚拟化技术

IT之家5月21日消息,科技媒体linuxiac昨日(5月20日)发布博文,报道称代号为SageMargay的AlmaLinux9.6发行版已上线,距上一版本9.5发...

跟老韩学Linux运维架构师系列,vim与view的基本使用

下面是vim和view的10个实例:用vim打开一个新文件:vimnewfile.txt这个命令将会在vim编辑器中打开一个新文件。在vim中移动光标:使用方向键或h、j、k、l键来移动光标。在v...

malloc底层原理剖析——ptmalloc内存池

malloc底层为什么是内存池malloc大家都用过,其是库函数。我们都知道库函数在不同的操作系统中其实执行的是系统调用,那么malloc在Linux上执行的是哪个系统调用呢?brk()和mmap()...

Zen 6架构首秀Linux,AMD加速下一代处理器布局

IT之家5月15日消息,科技媒体Phoronix昨日(5月14日)发布博文,报道称AMD已经开始为下一代“Zen6”处理器做准备,已为该构架向Linux内核提交了首个补丁,...

为何越来越多企业转向安卓/Linux工业平板电脑?答案在这里

在工业领域,设备的稳定性至关重要,尤其是工业平板电脑,常年运行在高温、粉尘、潮湿等复杂环境下,一旦系统崩溃或者卡顿,可能会影响整个生产流程。那么,为什么越来越多的企业选择安卓/Linux工业平板电脑,...

从3ms到0.8ms:ARM+Linux如何重塑工业控制实时性标杆

在智能制造领域,产线控制系统对实时性的要求越来越高。根据行业调研数据,超过65%的工业现场出现过因系统响应延迟导致的故障停机,平均每次停机造成的直接损失高达2-8万元。传统x86架构搭配Windows...

看Linux如何&quot;挖坑种树&quot;

写在前面,有人看我的Linux文章说技术难度不深,笔者不是不想写深,笔者是觉得Linux难就难在入门,入门之后你就知道如何上网查询你所要要解决的Linux需求。如果你已入门,此文已对你无用,请略过此...

AlmaLinux 9.6 发布,新增功能亮点纷呈!

距离上一版本AlmaLinux9.5发布六个月后,基于5.14内核的AlmaLinux正式宣布其企业级Linux发行版的9.x系列第六个更新——AlmaLinux9.6(Sag...