首页 > 其他分享 >线程不安全函数学习

线程不安全函数学习

时间:2023-07-30 21:23:14浏览次数:38  
标签:end 函数 学习 start tm 线程 localtime

转自: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时还没有多线程技术,所以很多函数内部使用了全局变量或函数内部的静态变量。随着多线程技术的出现,很多函数都有了对应的多线程安全版本。

 

标签:end,函数,学习,start,tm,线程,localtime
From: https://www.cnblogs.com/BlueBlueSea/p/17592058.html

相关文章

  • C++ Primer 学习笔记——第八章
    第八章IO库前言C++语言并不会直接处理输入输出,而是通过一族定义在标准库中的类型来处理IO。这些类型支持从设备中读取数据、向设备写入数据IO操作。设备可以是文件、控制台窗口等,还有一些类型允许内存IO。IO库定义了读写内置类型值的操作。8.1IO类在之前我们使用的IO类型......
  • 欧拉函数
    欧拉函数的几个性质(以下\(p\)无特殊说明,都为质数):若\(gcd(a,b)=1\),则\(\varphi(a)\times\varphi(b)\),证明不会,大家记住就行了\(n=\sum_{d|n}\varphi(d)\)证明:设\(f(x)\)表示\(gcd(k,n)=x\)的数的个数(\(k<=n\))结论:\(n=\sum_{i=1}^nf(i)\)我们可以分类讨论(保证......
  • python数据分析师入门-学习笔记(爬虫-序言)
    爬虫到底是什么概括爬虫是批量化自动获取既有数据批量化自动既有数据通常获取既有数据特殊批量注册一批账号批量去领取优惠券批量自动下单购物自动做任务(签到)实际应用企业中:竞品调研数据采集办公自动化个人:比如看小说有的网站收费有的网站不收费......
  • rabbitmq学习
    rabbitmq学习,rabbitmq教程,rabbitmq安装作用:1、削蜂,2、解耦3、异步处理核心概念:交换机、队列、信道 官网网址:https://www.rabbitmq.com/download.htmldocker安装:dockerrun-it--rm--namerabbitmq-p5672:5672-p15672:15672rabbitmq:3.12-management 默认用......
  • 【机器学习】单变量线性回归
    MLintroduction机器学习:从数据中学习,而不依赖于规则下编程的一种算法Goal:\(min_{w,b}(J(w,b))\)-提供一种衡量一组特定参数与训练数据拟合程度的方法SupervisedLearningrightanswer&&x->ylabelcategoriesRegressionClassificationUnsupervisedLearnin......
  • Spring Boot学习路线1
    SpringBoot是什么?SpringBoot是基于SpringFramework构建应用程序的框架,SpringFramework是一个广泛使用的用于构建基于Java的企业应用程序的开源框架。SpringBoot旨在使创建独立的、生产级别的Spring应用程序变得容易,您可以"只是运行"这些应用程序。术语SpringCore是Spring......
  • React(十二):props的函数组件中使用
    <!DOCTYPEhtml><html><head><metacharset="utf-8"><title>props的函数组件实现</title><scriptsrc="https://unpkg.com/react@18/umd/react.development.js"></script><scriptsr......
  • C++ Primer Plus 第6版 读书笔记(8)第 8章 函数探幽
    第8章函数探幽本章内容包括:内联函数。引用变量。如何按引用传递函数参数。默认参数。函数重载。函数模板。函数模板具体化。通过第7章,您了解到很多有关C++函数的知识,但需要学习的知识还很多。C++还提供许多新的函数特性,使之有别于C语言。新特性包括内联函数、......
  • 关于菜鸡学习RHEL8的一些小笔记--->磁盘分区
    磁盘分区磁盘分区表:MBR表(系统盘使用较多):单块硬盘或者是单个阵列的最大支持2T,并且只能支持四个分区#因为MBR分区类型较多,实际是可以做到分四个以上的分区分区类型:主分区,扩展分区,逻辑分区(逻辑驱动器)GPT表(业务盘使用较多):单块磁盘或者阵列的最大支持是8Z,并且支持128个分区数量(实际上G......
  • 【学习】最小生成树-Prim
    最小生成树(Prim)学习笔记展开目录目录最小生成树(Prim)学习笔记BeforePrim核心思想堆优化例题挖水井Before为了做个挖水井去学了Prim虽然根本不是算法的锅前置知识是\(dijkstra\),有一定相似度Prim\(Kruskal\)是一种适用于稀疏图的算法,而对于稠密图,也有其适用的算法—......