C库的非线程安全函数,以localtime函数为例

C++
1082 0

1. 引言

localtime函数为例,有如下代码:

#include <iostream>
#include <time.h>

int main() {
    time_t start = time(NULL);
    time_t end = start + 1000;

    struct tm* ptm_start = localtime(&start);    //  <--------
    struct tm* ptm_end = localtime(&end);    // <--------

    char str_start[64] = { 0 };
    char str_end[64] = { 0 };
    strftime(str_start, 64, "%H:%M:%S", ptm_start);
    strftime(str_end, 64, "%H:%M:%S", ptm_end);

    printf("start: %s\n", str_start);
    printf("  end: %s\n", str_end);

    return 0;
}

输出结果:

$ ./out
start: 17:52:55
  end: 17:52:55

两个时间差了1000秒,但是输出结果却一样。

2. 原因

localtime函数签名如下:

struct tm* localtime(const time_t* timep);

函数返回的是一个指针,但是外部却不需要释放这个指针指向的内存,因此其内部使用了一个全局变量或函数内部的静态变量。

因此两次调用该函数,第2次的结果就覆盖了第1次的结果(二者返回的指针指向同一个地址)。

上述例子中有如下条件成立:

    ptm_start == ptm_end;   // true

3. 解决方案

使用线程安全的函数localtime_r替代。

#include <iostream>
#include <time.h>

int main() {
    time_t start = time(NULL);
    time_t end = start + 1000;

    struct tm tm_start;
    struct tm tm_end;
    localtime_r(&start, &tm_start);
    localtime_r(&end, &tm_end);

    char str_start[64] = { 0 };
    char str_end[64] = { 0 };
    strftime(str_start, 64, "%H:%M:%S", &tm_start);
    strftime(str_end, 64, "%H:%M:%S", &tm_end);

    printf("start: %s\n", str_start);
    printf("  end: %s\n", str_end);

    return 0;
}

输出结果正确

$ ./out
start: 17:55:21
  end: 18:12:01

4. 小结

C库中存在一些非线程安全函数,因为最初编写CRT时还没有多线程技术,所以很多函数内部使用了全局变量或函数内部的静态变量。随着多线程技术的出现,很多函数都有了对应的多线程安全版本。

最后更新 2022-12-17
评论 ( 0 )
OωO
隐私评论