(C++) this_thread 函数介绍

文章目录

  • 🚩前言
  • ⭐std::this_thread
    • 🕹️get_id()
      • 🖥️Code
      • 🔖get_id介绍
      • 🏷️其他介绍
    • 🕹️sleep_for<>()
      • 🖥️Code
      • 🔖sleep_for介绍
      • 🏷️其他介绍
    • 🕹️sleep_until<>()
      • 🖥️Code
      • 🔖sleep_until介绍
      • 🏷️其他介绍
    • 🕹️yield()
      • 🖥️Code
      • 🔖yield介绍
      • 🏷️其他介绍
  • 🚩END

🚩前言

在C++11起,标准规定了标注的并发库。头文件为#include <thread> 并发支持库 (C++11 起) - cppreference.com

其包含线程、原子操作、互斥、条件变量和 future 的内建支持。

而其中有一个namespacethis_thread,里面有四个重要的全局函数,其实现都与当前系统环境和编译器强绑定。

std::this_thread 符号索引 - cppreference.com

  • get_id()
  • sleep_for<>()
  • sleep_until<>()
  • yield()

⭐std::this_thread

🕹️get_id()

std::this_thread::get_id - cppreference.com

🖥️Code

#include <iostream>
#include <string>
#include <thread>

void show_thread_id(std::string msg) {
    std::cout << msg << " = " << std::this_thread::get_id() << std::endl;
}

int main() {
    auto id = std::this_thread::get_id();
    std::cout << "std::this_thread::get_id() = " << typeid(id).name() << std::endl;
    show_thread_id("main");

    for (int i = 0; i < 3; i += 1) {
        std::thread th(show_thread_id, "son-thread");
        if (th.joinable()) {
            th.join();
        }
    }
}

🔖get_id介绍

std::thread::id get_id() noexcept;

返回当前线程的 id

这个id是一个std::thread的内部类型std::thread::id。其实现依附于所在平台。

# msvc-x64
std::this_thread::get_id() = class std::thread::id
main = 13232
son-thread = 3908
son-thread = 3724
son-thread = 4840

# mingw-w64
std::this_thread::get_id() = NSt6thread2idE
main = 1
son-thread = 2
son-thread = 3
son-thread = 4
# msvc-x64
std::thread::id::_Thrd_id_t _Id;
using _Thrd_id_t = unsigned int;

# mingw-w64
std::thread::id::native_handle_type _M_thread;
using native_handle_type = __gthread_t;
typedef pthread_t __gthread_t;
typedef uintptr_t pthread_t;
__MINGW_EXTENSION typedef unsigned __int64 uintptr_t;
#define __int64 long long

🏷️其他介绍

C语言获取线程id或句柄

msvc-x64

#include <stdio.h>
#include <windows.h>

int main() {
    DWORD thread_id = GetCurrentThreadId();
    printf("Current thread ID: %lu\n", thread_id);

    HANDLE thread_handle = GetCurrentThread();
    printf("Current thread HANDLE: %p\n", thread_handle);
    return 0;
}
Current thread ID: 24904
Current thread HANDLE: FFFFFFFE

mingw-w64

#include <pthread.h>
#include <stdio.h>

int main() {
    pthread_t thread_id = pthread_self();
    printf("Current thread ID: %ld\n", (long)thread_id);
    return 0;
}
Current thread ID: 1

🕹️sleep_for<>()

std::this_thread::sleep_for - cppreference.com

🖥️Code

#include <chrono>
#include <ctime>
#include <iostream>
#include <thread>

class Timer {
private:
    std::string  hint;
    std::clock_t curTime = 0;

public:
    Timer(const std::string& str = "") : hint(str) {
        curTime = std::clock();
    }

    ~Timer() {
        std::clock_t endTime = std::clock();
        std::cout << hint << " : ";
        std::cout << 1.0 * (endTime - curTime) / 1000 << std::endl;
    }
};

int main() {
    Timer timer("main");
    std::this_thread::sleep_for(std::chrono::seconds(2));
}
main : 2.004

🔖sleep_for介绍

template< class Rep, class Period >
void sleep_for( const std::chrono::duration<Rep, Period>& sleep_duration );

阻塞当前线程执行,至少 经过指定的 sleep_duration。

因为调度或资源争议延迟,此函数可能阻塞长于 sleep_duration。

标准库建议用稳定时钟度量时长。若实现用系统时间代替,则等待时间亦可能对时钟调节敏感。

异常

clocktime_pointduration 在执行间抛出的任何异常(标准库提供的时钟、时间点和时长决不抛出)。

🏷️其他介绍

这里使用了一个RAII的技巧来测试计时

(C++) 基于RAII的简单计时器_哔哩哔哩_bilibili

计时的方式比较多,这里采用的是C语言的<time.h>库。(C语言) time库-日期和时间工具 -CSDN博客

而C++也有增强的<chrono>库。

🕹️sleep_until<>()

std::this_thread::sleep_until - cppreference.com

🖥️Code

#include <chrono>
#include <iostream>
#include <string>
#include <thread>

using chrono_time_point = std::chrono::high_resolution_clock::time_point;
using chrono_ms         = std::chrono::milliseconds;

void show_time_point(chrono_time_point point, std::string msg) {
    intmax_t ns = std::chrono::duration_cast<chrono_ms>(point.time_since_epoch()).count();
    std::cout << msg << " : " << ns << " ms" << std::endl;
}

int main() {
    chrono_time_point startStamp  = std::chrono::high_resolution_clock::now();
    chrono_time_point targetStamp = startStamp + std::chrono::seconds(3);

    // 设置延时的目标时间
    std::this_thread::sleep_until(targetStamp);
    chrono_time_point endStamp = std::chrono::high_resolution_clock::now();

    show_time_point(startStamp, "startStamp");
    show_time_point(targetStamp, "targetStamp");
    show_time_point(endStamp, "endStamp");
}
startStamp : 1713801775996 ms
targetStamp : 1713801778996 ms
endStamp : 1713801779004 ms

🔖sleep_until介绍

template< class Clock, class Duration >
void sleep_until( const std::chrono::time_point<Clock, Duration>& sleep_time );

阻塞当前线程的执行,直至抵达指定的 sleep_time。

Clock 必须符合时钟 (Clock) 要求。如果 std::chrono::is_clock_v 是 false,那么程序非良构。 (C++20 起)

标准推荐使用绑定到 sleep_time 的时钟,此时调整时钟会有影响。因此,阻塞的时长可能会小于或大于调用时的 sleep_time - Clock::now(),这取决于调整的方向以及实现是否尊重这样的调整。函数也可能会因为调度或资源纠纷延迟而阻塞到 sleep_time 之后的某个时间点。

异常

ClockDuration 抛出的任何异常(标准库提供的时钟和时长决不抛出)。

🏷️其他介绍

std::chrono::time_point的实际类型也是基于实际实现的。

而其重载了 operator +()可以与std::duration<>进行运算,因此其对时间的运算更加的自由。

而重新转换又需要使用std::chrono::duration_cast<>来处理,

最后的count()返回值取决于duration<_Rep, _Period>::_Rep

而其在实现层面,一般默认会使用整形能获取的最大值,

一般使用intmax_t

上面代码为了展现实际的数据类型而全部写了出来,实际编程中这些太冗余了。

局部变量的话建议直接写auto,跨范围的用using规定一个别名。

🕹️yield()

std::this_thread::yield - cppreference.com

🖥️Code

#include <atomic>
#include <iostream>
#include <thread>

/**
 * 简单实现自旋锁
 */
struct SpinLock {
    std::atomic_flag flag = {ATOMIC_FLAG_INIT};

    void lock() {
        // 循环自旋
        while (flag.test_and_set(std::memory_order_acquire)) {
            // 自旋的时候让出调度权,提升cpu效率
            std::this_thread::yield();
        }
    }

    void unlock() {
        flag.clear(std::memory_order_release);
    }
};

SpinLock spinlock;
int      x = 0;

void thread_func() {
    for (int i = 0; i < 100000; i += 1) {
        spinlock.lock();
        x += 1;
        spinlock.unlock();
    }
}

int main() {
    std::thread th1(thread_func);
    std::thread th2(thread_func);

    th1.join();
    th2.join();

    std::cout << x << std::endl;
}

🔖yield介绍

void yield() noexcept;

向实现提供一个提示,重新调度线程的执行以允许其他线程运行。

注意

此函数的确切行为依赖于实现,特别是取决于使用中的 OS 调度器机制和系统状态。例如,先进先出实时调度器(Linux 的 SCHED_FIFO)会挂起当前线程并将它放到准备运行的同优先级线程的队列尾(而若无其他线程在同优先级,则 yield 无效果)。

🏷️其他介绍

yield()与当前系统的任务调度策略强依赖。

上述代码是一个自旋锁的简单实现,注意在实践中自旋锁通常是错误。

就是通过原子的读改写达到阻塞进入临界区的作用。

std::atomic_flag - cppreference.com

std::atomic_flag是C++11中的一个原子布尔类型,与std::atomic<bool>不同,它保证了是免锁的。

(构造函数)构造 atomic_flag (公开成员函数)
operator=赋值运算符 (公开成员函数)
clear原子地设置标志为 false (公开成员函数)
test_and_set原子地设置标志为 true 并获得其先前值 (公开成员函数)
test(C++20)原子地返回标志的值 (公开成员函数)
wait(C++20)阻塞线程直至被提醒且原子值更改 (公开成员函数)
notify_one(C++20)提醒至少一个在原子对象上的等待中阻塞的线程 (公开成员函数)
notify_all(C++20)提醒所有在原子对象上的等待中阻塞的线程 (公开成员函数)

可以见得,在C++20中std::atomic_flag能够达到通知阻塞的作用,这极大的可以优化有传统条件变量的通知。

能够有更小的开销,对一些库的性能提升非常大。

🚩END

关注我,学习更多C/C++,算法,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/571202.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python基础语法--列表

一、列表的概念 列表&#xff08;List&#xff09;是一种有序、可变、允许重复元素的数据结构。列表用于存储一组相关的元素&#xff0c;并且可以根据需要动态地进行增加、删除、修改和访问。以下是列表的主要特点和操作&#xff1a; 有序性&#xff1a; 列表中的元素是按照它…

最新AI创作系统ChatGPT网站源码Midjourney-AI绘画系统,Suno-v3-AI音乐生成大模型。

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

【CVPR2024】文本到图像的行人再识别中的噪声对应学习

这篇论文的标题是《Noisy-Correspondence Learning for Text-to-Image Person Re-identification》,作者是来自中国四川大学、英国诺森比亚大学、新加坡A*STAR前沿人工智能研究中心和高性能计算研究所的研究人员。论文主要研究了文本到图像的行人再识别(Text-to-Image Person…

Unity进阶之ScriptableObject

目录 ScriptableObject 概述ScriptableObject数据文件的创建数据文件的使用非持久数据让其真正意义上的持久ScriptableObject的应用配置数据复用数据数据带来的多态行为单例模式化的获取数据 ScriptableObject 概述 ScriptableObject是什么 ScriptableObject是Unity提供的一个…

Windows抛弃历史包袱:可能带来哪些改善?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 Windows的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;性能提升固然重要&#xff0…

[NSSCTF]-Reverse:[HUBUCTF 2022 新生赛]simple_RE(base64换表)

无壳 查看ida 可以看得出是base64&#xff0c;而且是换表的。 完整exp&#xff1a; import base64 result5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8 biaostr.maketrans(qvEJAfHmUYjBacu8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD,ABCDEFGHIJKLMNOPQR…

BUUCTF---misc---[SWPU2019]我有一只马里奥

1、下载附件是一个.exe文件 2、运行之后可以看到桌面生成了1.txt文件&#xff0c;文件里面有如下内容 3、经过信息搜索&#xff1a;NTFS&#xff08;New Technology File System&#xff09;是一种由Microsoft开发的专有日志文件系统。根据它的提示&#xff0c;应该是把flag.tx…

编译原理 LR(0)

讲解视频&#xff1a;编译原理LR&#xff08;0&#xff09;分析表&#xff08;上&#xff09;_哔哩哔哩_bilibili 【编译原理】LR(0)分析表分析输入串_哔哩哔哩_bilibili 拓广文法 已知G&#xff1a;S->(S)S | ε 拓广文法&#xff1a; S -> S S -> (S)S S -> ε…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(二)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 3 - 4节&#xff09; P3《开发准备-了解ArkTS》 鸿蒙开发主要是用来开发移动端应用的。 以前我们开发移动端应用的代码&#xff…

嵌入式4-24

作业&#xff1a; 整理思维导图 定义一个矩形类Rec&#xff0c;包含私有属性length&#xff0c;width&#xff0c;有以下成员函数&#xff1a; void set_length(int l); //设置长度 void set_width(int w); //设置宽度 int get_length(); //获取长度 int get_width(); //获取宽…

【Spring】IOC/DI中常用的注解@Order与@DependsOn

目录 1、Order 注解改变Bean自动注入的顺序 1.1、了解SpringBootTest注解 1.2、Order 注解改变Bean自动注入的顺序 2、DependsOn 改变Bean的创建顺序 1、Order 注解改变Bean自动注入的顺序 在sping中&#xff0c;通过IOC&#xff08;控制反转&#xff09;和DI&#xff08;依…

【分治】Leetcode 数组中的第K个最大元素

题目讲解 数组中的第K个最大元素 算法讲解 堆排序&#xff1a;1. 寻找最后一个节点的父亲&#xff0c;依次向上遍历&#xff0c;完成小堆的建立&#xff1b;2. 从最后一个元素开始&#xff0c;和堆顶的数据做交换&#xff0c;此时最小的数据在对后面&#xff0c;然后对剩下的…

虚幻引擎5 Gameplay框架(一)

GamePlay概论与打包和批处理脚本 GamePlay简介与创建项目 GamePlay框架&#xff1a;用于设计游戏规则&#xff0c;组织和管理游戏核心逻辑、规则以及交互的一套结构化体系。 Default Pawn Class&#xff1a;定义角色行为逻辑&#xff0c;接收玩家控制器的输入&#xff0c;一般…

Linux 基础IO(2)磁盘文件

文章目录 1.磁盘文件2.文件系统3.软硬链接1.软链接2.硬链接 4.动静态库1.静态库2.动态库 1.磁盘文件 扇区&#xff1a;整个盘片分成不同的区块&#xff0c;每一个区块就是一个扇区。 扇区是磁盘IO的基本单位&#xff0c;一般为512Byte或4KB,一般磁盘都是512Byte磁道&#xff1a…

Mysql 查询表参考

基本操作 数据库和表的基础操作_数据库和表的基本操作-CSDN博客文章浏览阅读222次。数据库基础知识_数据库和表的基本操作https://blog.csdn.net/weixin_67573348/article/details/126946843 单表 语法分析&#xff1a;MySQL 单表查询 语法分析_adn查询-CSDN博客文章浏览阅读…

CTFHub(web sql注入)(三)

MYSQL 手工注入 1.判断字段数 输入1 输入2 输入3 得知字段有两个 2.判断注入类型 1 and 1 1 1 and 12 回显错误&#xff0c;说明存在sql注入 3.查看数据库内容 知道字段数量为2后&#xff0c;可以查看数据库位置 1 union select 1,2 使用union select 1,2查看未发现数…

【2023】springboot通过阿里云oss进行文件单个批量文件上传下载

SpringBoot整合阿里OSS实现上传下载 目录&#x1f4bb; 前言一、介绍二、阿里云添加oss1、进入oss目录2、创建bucket3、测试上传下载4、创建AccessKey管理账号 三、依赖以及配置1、依赖2、yml3、Config类4、OSSUtil 工具类 四、controller五、测试1、测试上传2、测试删除 前言 …

【调制】π/4-DQPSK信号模型及其相关特性分析 【附MATLAB代码】

MATLAB代码 % pi/4-DQPSK modulation %输入一串数&#xff0c;输出经过差分并映射的I、Q两路数据 ​ function [I,Q]pi4_dqpskmod(data) ​ nlength(data)./2; data1data.*2-1; ​ Idatazeros(1,n); Qdatazeros(1,n); ​ ​ Idatadata1(1,1:2:2*n); %串并变换 Qdatadata1(…

用户中心 -- 代码理解

一、删除表 & if 删除表 1.1 DROP TABLE IF EXISTS user 和 DROP TABLE user 网址&#xff1a; 用户管理第2节课 -- idea 2023.2 创建表--【本人】-CSDN博客 二、 代码 2.1 清空表中数据 的 命令 【truncate 清空】 网址&#xff1a; 用户管理第2节课 -- idea 2…

卡尔曼滤波器(二):Simulink卡尔曼滤波器模块使用

观看MATLAB技术讲座笔记&#xff0c;该技术讲座视频来自bilibili账号&#xff1a;MATLAB中国。 本节在Simulink中用卡尔曼滤波器来滤除传感器噪声&#xff0c;准确估算单摆摆角。 一、单摆模型简介 不考虑摩擦时&#xff0c;下图所示的单摆力学平衡方程为&#xff1a; m l 2…