(C++) this_thread 函数介绍

news2025/1/13 15:51:16

文章目录

  • 🚩前言
  • ⭐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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第三节课,后端登录【1】

一、总任务 二、登录接口 get 请求&#xff0c;有缺陷&#xff0c;长度有限制 三、登录逻辑 四、代码书写位置 4.1 编写业务逻辑的位置 五、写代码 5.1 代码1 5.1.1 细节 按 CtrlAltShiftL ,快速格式化 5.1. 2 自动生成接口参数 先/** 再回车 效果图 5.2 按 alt enter …

数据结构练习-算法与时间复杂度

----------------------------------------------------------------------------------------------------------------------------- 1. 设n是描述问题规模的非负整数&#xff0c;下列程序段的时间复杂度是( )。 x0;while(n>(x1)*(x1)xx1; A.O(logn) B.O(n^(1/2)) C.O(n)…

ubuntu无法用快捷键启动终端(CTRL+AIT+T)

我的电脑不知道安装什么东西之后&#xff0c;就不能用快捷键&#xff08;CTRLAITT&#xff09;打开终端了 只能在文件夹内&#xff0c;点击鼠标右键选择终端&#xff0c;然后打开终端 一直这么用了几个月&#xff0c;今天实在受不了了&#xff0c;所以解决此问题 本文参考文章…

Seata 的AT模式写隔离问题,求大佬解答。

引用Seata 是什么&#xff1f; | Apache Seata AT 模式 前提​ 基于支持本地 ACID 事务的关系型数据库。Java 应用&#xff0c;通过 JDBC 访问数据库。 整体机制​ 两阶段提交协议的演变&#xff1a; 一阶段&#xff1a;业务数据和回滚日志记录在同一个本地事务中提交&…

岭回归(概念+实例)

目录 前言 一、基本概念 1. 引言 2. 岭回归的原理 3. 数学表达式 4. 岭回归的优点 5. 岭回归的局限性 6. 实际应用 二、具体实例 前言 “岭回归”这个词源于英文“Ridge Regression”&#xff0c;是一种用于处理回归分析中多重共线性&#xff08;multicollinearity&am…

java-spring-mybatis -学习第一天-基础知识讲解

目录 前置条件(创建一个项目) Mybatis 定义 可能出现的问题 这边如果连接不上数据库 ​编辑 Dao接口设计 Mybatis流程 创建实体类 User 和其属性 创建Mapper的接口类 测试类测试 实例数据库数据的更新 实例数据库数值的删除 最重要的是有一个原始的数据库 -我这边…

传统行业还在使用FTP传输?试试这套FTP替代传输解决方案!

在数字化转型的浪潮中&#xff0c;传统企业对文件传输的需求日益增长。然而&#xff0c;许多企业仍在使用传统的文件传输协议&#xff08;FTP&#xff09;来处理文件传输任务。尽管FTP在早期被广泛采用&#xff0c;但其固有的弊端逐渐成为企业发展的桎梏&#xff0c;所以找一个…

SQL中的锁

一、概述 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资(CPU、RAM、I/0)的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁冲…

大模型 AI 框架昇思 MindSpore 2.3.RC1 发布,训练、推理性能大幅提升,JIT 编译强化

经过社区开发者们几个月的开发与贡献&#xff0c;现正式发布昇思 MindSpore2.3.RC1 版本&#xff0c;通过多维混合并行以及确定性 CKPT 来实现超大集群的高性能训练&#xff0c;支持大模型训推一体架构&#xff0c;大模型开发训练推理更简、更稳、更高效&#xff0c;并在训推一…

【CMU15-445 Part-19】Multi-Version Concurrency Control

Part19-Multi-Version Concurrency Control 其实说到底 MVCC不仅是一种并发控制协议&#xff0c;更是一个系统构建&#xff08;数据组织的方法&#xff09;。 简介 writer 不会 block readers&#xff0c;reader 也不会 block writers。只读事务可以读到一个consistent的sna…

nlp 自然语言处理的dataset数据库积累

下面的这个和 entity recognition有关的。 Weights & Biases

光伏无人机巡检主要有些什么功能和特点?

随着科技的飞速发展&#xff0c;无人机技术已经渗透到多个行业领域&#xff0c;光伏产业便是其中之一。光伏无人机巡检&#xff0c;作为一种新兴的巡检方式&#xff0c;正在逐渐取代传统的人工巡检&#xff0c;为光伏电站的安全、高效运行提供了有力保障。那么&#xff0c;光伏…

10:00面试,10:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

“我也想和月牙一样,把不满写在脸上”

贪吃蛇的初级实现 1. Win32 API介绍1.1 Win32 API1.2 控制台程序1.3 控制台屏幕上的坐标COORD1.4 GetStdHandle1.5 GetConsoleCursorInfo1.5.1 CONSOLE_CURSOR_INFO 1.6 SetConsoleCursorInfo1.7 SetConsoleCursorPosition1.8 GetAsyncKeyState 2. 贪吃蛇游戏设计与分析2.1 地图…

使用Shell终端访问Linux

一、实验目的 1、熟悉Linux文件系统访问命令&#xff1b; 2、熟悉常用 Linux Shell的命令&#xff1b; 3、熟悉在Linux文件系统中vi编辑器的使用&#xff1b; 4、进一步熟悉虚拟机网络连接模式与参数配置&#xff01; 二、实验内容 1、使用root帐号登陆到Linux的X-windows…

2024年了,还有必要搭建企业网站吗?

现在企业的营销手段五花八门。当下火爆的短视频直播平台展现出的裂变效应也取得不错的成绩&#xff0c;这不禁让很多企业舍弃做网站的念头&#xff0c;投入自媒体账号。那么&#xff0c;2024年了&#xff0c;还有必要搭建企业网站吗&#xff1f; 我们分两种企业来看&#xff1…

【11-Ⅱ】Head First Java 学习笔记

HeadFirst Java 本人有C语言基础&#xff0c;通过阅读Java廖雪峰网站&#xff0c;简单速成了java&#xff0c;但对其中一些入门概念有所疏漏&#xff0c;阅读本书以弥补。 第一章 Java入门 第二章 面向对象 第三章 变量 第四章 方法操作实例变量 第五章 程序实战 第六章 Java…

3d软件哪个适合新手学?3D动画渲染怎么好

在不同的行业领域&#xff0c;3D建模和动画的需求各异&#xff0c;因此所需的3D软件工具也会有所不同。对于刚开始接触3D设计的新手来说&#xff0c;软件的易操作性、丰富的学习资源以及与自己专业领域相关的功能是选择时的重要考虑因素。以下是几款适合初学者入门的3D软件推荐…

【第3节】“茴香豆“:搭建你的 RAG 智能助理

目录 1 基础知识1.1.RAG技术的概述1.2 RAG的基本结构有哪些呢&#xff1f;1.3 RAG 工作原理&#xff1a;1.4 向量数据库(Vector-DB )&#xff1a;1.5 RAG常见优化方法1.6RAG技术vs微调技术 2、茴香豆介绍2.1应用场景2.2 场景难点2.3 茴香豆的构建&#xff1a; 3 论文快读4 实践…

OpenHarmony网络协议通信—libevent [GN编译] - 事件通知库

libevent主要是用C语言实现了事件通知的功能 下载安装 直接在OpenHarmony-SIG仓中搜索libevent并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 库代码存放路径&#xff1a;./third_party/libevent 修改添加依赖的编译脚本 在/developtools/bytrace_standard/…