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

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

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

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 的时间戳计数器等)来生成秒数和纳秒数,确保时间是单调递增的。

相关推荐

PC也能装MAX OS X

MACBOOK向来以其时尚的外观以及易用的OSX操作系统成为了时(zhuang)尚(bi)人士的最爱。但是其动不动就上万元的昂贵价格,也将一批立志时(zhuang)尚(bi)人士的拒之门外。但是最近...

一千多元的笔记本能买吗?英特尔11代+大屏幕,豆小谷值得选吗?

前言:有很多粉丝都问过本人,一千多元到底能买到什么样的笔记本?在此笔者只想说,这样的资金预算真的太低了!如果想买全新的,那大概率买的就是性能比较拉垮的上网本,比如搭载英特赛扬N系列、J系列处理器的轻薄...

首款配备骁龙X Elite处理器的Linux笔记本:采用KDE Plasma桌面环境

德国Linux硬件供应商TUXEDOComputers宣布正在开发一款配备高通骁龙XElite处理器(SnapdragonXEliteSoC)的ARM笔记本电脑,内部将该...

System76推出Gazelle Linux笔记本:配酷睿i9-13900H处理器

IT之家3月30日消息,主打Linux硬件的厂商System76于今天发布了新一代Gazelle笔记本电脑,共有15英寸和17英寸两个版本,将于3月30日接受预订,...

Kubuntu Focus Xe Gen 2笔记本发布,预装Linux系统

IT之家3月25日消息,KubuntuFocusXeGen2笔记本于近日发布,这是一款预装Kubuntu22.04LTSGNU/Linux发行版的轻薄本。上一代Kub...

这台Linux笔记本已用上英特尔12代酷睿,最高可选i7-1255U、卖1149美元起

Linux笔记本可能因为比较小众,一般都是拿Windows笔记本换个系统而来,硬件上也会落后同期Windows笔记本一两代,不过现在专门做Linux电脑的System76,推出了一款名为LemurP...

戴尔Inspiron 14 Plus骁龙笔记本迎新补丁,支持启动Linux

IT之家4月25日消息,科技媒体phoronix今天(4月25日)发布博文,报道称最新发布的Linux内核补丁,针对骁龙芯片的戴尔Inspiron14Plus笔记本,让其...

TUXEDO推出InfinityFlex 14二合一Linux笔记本,配i5-1335U

IT之家8月12日消息,Linux硬件企业TUXEDO当地时间本月2日推出了InfinityFlex14二合一Linux笔记本。该笔记本搭载2+8核的英特尔酷睿i5-...

登月探测器嫦娥使用什么操作系统,是Linux还是其它自主研发?

这是不是国家机密啊。事实什么样的不知道,但是从美国的探测器来看,就算不是也是相似的东西。下面我来说说我知道的。龙芯已经随北斗卫星上天了.就算登月探测器嫦娥是用"龙芯+Linux"也不出奇.没必要...

DNS分离解析实验

如果本文对你有帮助,欢迎关注、点赞、收藏、转发给朋友,让我有持续创作的动力目录一、分离解析概述二、实验需求三、实验步骤3.1双网卡服务器配置3.1.1添加两张网卡(内外网)3.1.2对两个网卡进...

一个小实验巩固下进程管理

先回顾下之前的三篇文章:Linux进程在内核眼中是什么样子的?Linux进程线程是如何创建的?Linux是如何调度进程的?通过这三篇文章的学习我们知道,无论内核进程还是用户进程,都是可以用task...

VMware Kali无线WIFI密码破解

WIFI破解前准备工作一张支持Kali系统监听的无线网卡VMware虚拟机安装好Kali系统(本实验用的是Kali2022版本)Kali系统下载、安装官方网站:https://www.kali.or...

python多进程编程

forkwindows中是没有fork函数的,一开始直接在Windows中测试,直接报错importosimporttimeret=os.fork()ifret==0:...

拔电源十台电脑藏后门!德国实验惊曝Windows致命漏洞

2025年4月15日,央视突然曝出一个超级大新闻!原来美国国家安全局通过黑龙江,往微软Windows系统里发送加密信息,激活了系统里藏着的后门程序,想破坏哈尔滨亚冬会!这消息一出来,大家才发现,竟然已...

深度探索RK3568嵌入式教学平台实战案例:设备驱动开发实验

一、产品简介TL3568-PlusTEB人工智能实验箱国产高性能处理器64位4核低功耗2.0GHz超高主频1T超高算力NPU兼容鸿蒙等国产操作系统二、实验目的1、熟悉基本字符设备的驱动程序...