线程不安全函数学习

转自:https://blog.csdn.net/qq_26499321/article/details/72085592,https://blog.icrystal.top/archives/13.html

1、线程不安全

  • 线程安全 就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 幂等。
  • 线程不安全 就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

1.1 分类

  • 不保护共享变量的函数。函数中访问全局变量和堆,需要通过同步机制来保护共享数据,比如加锁。
  • 返回指向静态变量的指针的函数。某些函数(如gethostbyname)将计算结果放在静态结构中,并返回一个指向这个结构的指针。在多线程中一个线程调用的结构可能被另一个线程覆盖。可以通过重写函数和加锁拷贝技术来消除。

2、举例localtime

std::localtime这个函数功能是将time_t转换成本地时间的结构体tm。是线程不安全的。

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

using namespace std;
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);

    cout<<"equal:"<<(ptm_start==ptm_end)<<"\n";//两者指向相同的地址
    return 0;
}

//输出:
start: 20:49:47
  end: 20:49:47
equal:1

输出结果却一样。localtime函数签名如下:

struct tm* localtime(const time_t* timep);

函数返回的是一个指针,但是外部却不需要释放这个指针指向的内存,因此其内部使用了一个全局变量或函数内部的静态变量。因此两次调用该函数,第2次的结果就覆盖了第1次的结果(二者返回的指针指向同一个地址)。

使用线程安全的函数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;
}


//输出:
start: 21:05:26
  end: 21:22:06
View Code

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

 

posted @ 2023-07-30 21:12  lypbendlf  阅读(58)  评论(0编辑  收藏  举报