C++ thread线程库

thread库

std::thread 是 C++ 标准库中的一个类,用于管理和控制单个执行线程。线程允许程序并行执行多个函数,从而提高性能和响应速度。std::thread 类提供了一种便捷的方式来创建和操作线程。

1、用途

并行执行任务: 通过 std::thread,可以同时执行多个函数。

多任务处理: 可以在不同的线程中处理不同的任务,使得程序可以同时完成多个任务。

资源共享和同步: 通过 std::thread,多个线程可以共享资源,如内存和文件。为避免数据竞争和冲突,通常会使用同步机制(如 std::mutexstd::atomic)来保护共享资源。

2、关键点

线程创建和启动std::thread 在构造时立即开始执行提供的函数。

线程同步joinable() 方法检查线程是否可以被 joindetach。调用 join() 会阻塞当前线程,直到目标线程完成。

3、线程的状态
  • 默认构造、移动构造、detachjoin 后,std::thread 对象将不再表示任何线程。
  • 两个 std::thread 对象不能表示同一执行线程,且 std::thread 不能复制,但可以移动。

一、类成员

id: 表示线程的id

std::thread::id
线程id唯一表示一个线程,一旦线程结束,这个id可以复用作为另一个线程的线程id;

在这里插入图片描述

二、成员函数

1、构造函数

用于构造新的thread对象

函数原型标准
thread() noexcept;(1)(C++11 起)
thread( thread&& other ) noexcept;(2)(C++11 起)
template< class Function, class… Args > explicit thread( Function&& f, Args&&… args );(3)(C++11 起)
thread(const thread&) = delete;(4)(C++11 起)

(1) 默认构造函数:构造一个不表示新线程thread对象,即不创建新线程。

(2) 移动构造函数:将other表示的执行线程的所有权转移给新创建的线程对象thread。调用后,thread表示执行线程,而other不再表示任何线程。

(3) 函数对象和参数列表:使用给定的函数和该函数的参数列表来创建并启动一个新线程。

(4) 复制构造函数:此构造函数被删除,因此thread对象不允许复制。

1)代码测试
#include <iostream>
#include <thread>
#include <chrono>
#include <string>

void func(int num,std::string str)
{
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << str <<" " << num << ":" << std::this_thread::get_id() << std::endl;
}

void func2()
{
    std::cout << "is func2" << std::endl;
}

int main()
{
    /*未启动线程*/
    // std::thread thread1; 
    // if(thread1.joinable())
    // {
    //     std::cout << "thread1 线程可被释放" << std::endl;
    //     thread1.join(); 
    // } else{
    //     std::cout << "thread1 线程不可被释放" << std::endl;
    // }

    //std::thread thread();
    // if(thread.joinable())    // 非法使用
    // {
    //     thread.join();   // 非法使用
    // }

    /*构造并启动*/
    // std::thread thread2(func,2,"thread2");
    // if(thread2.joinable())
    // {
    //     std::cout << "thread2 线程可被释放" << std::endl;
    //     thread2.join(); 
    // } else{
    //     std::cout << "thread2 线程不可被释放" << std::endl;
    // }    

    /*使用可调用对象和参数列表*/ 
    // std::thread thread4(func,4,"thread4");
    // if(thread4.joinable())
    // {
    //     thread4.join();
    //     std::cout << "t3 线程被释放" << std::endl;
    // } else{
    //     std::cout << "t3 线程不能被释放" << std::endl;
    // }

    /*移动构造*/ 
    // std::thread thread3(func,3,"thread3");
    // std::thread move_thread = std::move(thread3);
    // if(thread3.joinable())
    // {
    //     thread3.join();
    //     std::cout << "t3 线程被释放" << std::endl;
    // } else{
    //     std::cout << "t3 线程不能被释放" << std::endl;
    // }

    // if(move_thread.joinable())
    // {
    //     move_thread.join();
    //     std::cout << "move_thread 线程被释放" << std::endl;
    // } else{
    //     std::cout << "move_thread 线程不能被释放" << std::endl;
    // }

    /*复制构造*/
    // std::thread thread5(func,5,"thread5");
    // std::thread copy_thread(thread5);
    // thread5.join();
    // if(copy_thread.joinable())
    // {
    //     copy_thread.join();
    //     std::cout << "copy_thread 线程被释放" << std::endl;
    // } else{
    //     std::cout << "copy_thread 线程不能被释放" << std::endl;
    // }

    /*使用默认构造函数,延时启动线程*/
    // std::thread thread6; // 默认构造
    // thread6 = std::thread(func,6,"thread6");
    // if(thread6.joinable())
    // {
    //     thread6.join();
    //     std::cout << "thread6 线程被释放" << std::endl;
    // } else{
    //     std::cout << "thread6 线程不能被释放" << std::endl;
    // }

    return 0;
}
2)执行结果

在这里插入图片描述

2、析构函数

用于销毁 thread 对象,析构之前一定要保证没有正在运行的关联线程( 即joinable()返回true ),否则调用析构函数时会导致调用std::terminate(),从而终止程序 ,产生资源泄露和未定义行为。

注: std::terminate 函数 是一个用于处理未捕获异常的全局终止函数。当程序遇到未捕获的异常或者某些致命错误时,std::terminate 会被调用,通常会导致程序非正常退出。

函数原型标准
~thread();(C++11起)

在下列操作后 thread 对象无关联的线程(从而可安全销毁)

1.被默认构造,并没有被启动的线程对象
std::thread thread1;	// thread1没有被启动,则可以被安全销毁

2.被移动构造的线程对象
std::thread t2(func, argv);
std::thread t3(std::move(t2)); // 线程对象 t2 被移动后可以被安全销毁

3.调用了join()后的线程对象
t3.join();				// 线程对象 t3再调用 join()后,可以被安全销毁

4.调用了detach()后的线程对象
std::thread t4(func,argv);
t4.detach();			// 线程对象 t4 在调用detach()后可以被安全销毁

经过这些操作后,std::thread 对象不再与任何线程关联,可以安全销毁。这些操作确保在销毁 std::thread 对象时不会调用 std::terminate()

1)代码测试
#include <iostream>
#include <thread>
#include <chrono>

void func(std::string str)
{
    std::cout << str << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

int main()
{
    // std::thread t1(func,"t1");
    std::thread t2(func,"t2");
    std::thread t3(std::move(t2));
    std::thread t4(func,"t4");
    t3.join();
    t4.detach();
    return 0;
}
2)执行结果

在这里插入图片描述

3、运算符重载operator=

operator= 实际上是一个移动赋值运算符。它执行的是移动语义,将一个线程对象的所有权从一个 std::thread 对象转移到另一个 std::thread 对象。,类比移动构造。

4、joinable

检查 std::thread 对象是否活着。 若 thread 对象表示的执行线程活着则返回 true ,否则返回 false 。

函数原型标准
bool joinable() const noexcept;(C++11起)
1)代码测试
std::thread t1(func,argc);
if(t1.joinable())
	std::cout << "线程存活" << std::endl;
else
	std::cout << "线程死亡" << std::endl;

t1.join();
if(t1.joinable())
	std::cout << "线程存活" << std::endl;
else
	std::cout << "线程死亡" << std::endl;
2)执行结果

在这里插入图片描述

5、get_id

获取与线程对象关联的线程的 ID 。

  • std::this::thread::get_id(); 获取当前执行线程的ID;
  • std::thread 对象调用 get_id(),获取与该对象关联的线程ID;
函数原型标准
[std::thread::id]get_id() const noexcept;(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <thread>
#include <mutex>    // 互斥锁头文件

std::mutex mutex_lock;  // 定义互斥锁

void func(std::string str)
{
    std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全
    std::cout << "线程 " << str << " id = " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2)); 
}

int main()
{
    
    std::thread t1(func,"t1");
    std::thread t2(func,"t2");
    {
        std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全
        std::thread::id t1_id = t1.get_id();
        std::thread::id t2_id = t2.get_id();
        std::cout << "t1_id = " << t1_id << std::endl;
        std::cout << "t2_id = " << t2_id << std::endl;    
    }
    
    {
        std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全
        std::cout << "主线程 " << " id = " << std::this_thread::get_id() << std::endl;
    }
    t1.join();
    t2.join();
    return 0;
}

注:mutex_lock 是线程互斥锁,防止控制台输出竞争,输出信息混乱。关注get_id()函数的调用即可,使用互斥锁,是为了让了输出更美观,并获得正确的输出信息。

2)执行结果

在这里插入图片描述

在这里插入图片描述

6、native_handle

用于获取与 std::thread 对象关联的底层线程句柄。 std::thread 提供了一组基本的线程管理功能,但是在某些情况下,可能需要更低级的线程管理功能,例如设置线程优先级、绑定线程到特定的 CPU 核心、或其他特定于平台的操作。 如果需要与平台特定的 API 交互,native_handle() 可以获取底层线程句柄,从而进行更精细的控制。

函数原型标准
native_handle_type native_handle();(C++11 起)(可选)
1)代码测试
#include <iostream>
#include <thread>
#include <pthread.h>    // c线程库
#include <errno.h>
#include <string.h>

void func()
{
    std::cout << "thread ID = " << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::thread t(func);
    pthread_t nativeHandle = t.native_handle(); // 获取底层线程句柄

    // 设置线程优先级
    sched_param sch_params;
    sch_params.sched_priority = 20; // 设置优先级
    if (pthread_setschedparam(nativeHandle, SCHED_FIFO, &sch_params)) 
    {
        std::cerr << "设置线程调度失败: " << strerror(errno) << std::endl;
    }
    t.join();
    return 0;
}
2)执行结果

在这里插入图片描述

注:普通用户没有权限设置优先级,可以使用 sudo 获取临时管理员权限运行。

7、hardware_concurrency

返回支持的并发线程数,这个返回值因为系统资源限制、竞争条件、硬件支持等情况,该值只能做一个参考。

函数原型标准
static unsigned int hardware_concurrency() noexcept;(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mutex_lock;

void func(std::string str)
{
    std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全
    std::cout << "线程 " << str << " id = " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2)); 
}

int main()
{
    static unsigned int num = std::thread::hardware_concurrency();
    std::cout << "支持" << num << "个线程" << std::endl;
    return 0;
}
2)执行结果

在这里插入图片描述

8、join

用于阻塞当前线程,直到被 join() 的线程执行结束,被 join 的线程执行结束后,从对应的 join() 处返回。多个线程内,对同一个 std::thread 对象调用 join() 会导致未定义行为。

函数原型标准
void join();(C++11 起)

注: std::thread 对象调用 join()后,joinable() 结果为 false

1)代码测试
#include <iostream>
#include <thread>
#include <chrono>

void func(std::string str)
{
    std::cout << str << " " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

void func1(std::string str)
{
    std::cout << str << " " << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::thread t(func,"线程t");
    t.join();
    std::cout << "主线程: " << std::this_thread::get_id() << std::endl;

    std::thread t1(func1,"线程t1");
    std::thread t2([&t1]{
        t1.join();
    });
    std::thread t3([&t1] {
        t1.join();
    });
    t2.join();
    t3.join();
    return 0;
}
2)执行结果

在这里插入图片描述

9、detach

从 std::thread 对象分离执行线程,允许被分离的线程独立持续执行。该线程退出会自行释放资源,调用 detach 不再占有任何线程。

函数原型标准
void detach();(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <chrono>

void func(std::string str)
{
    std::cout << str << " " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t(func,"线程t");
    std::this_thread::sleep_for(std::chrono::seconds(2));
    t.detach();
    
    if(t.joinable())
    {
        std::cout << "线程t可被释放" << std::endl;
    }else{
        std::cout << "线程t自行释放" << std::endl;
    }
    return 0;
}
2)执行结果

在这里插入图片描述

10、swap

用于交换两个底层 std::thread 对象的句柄。

函数原型标准
void swap( [std::thread]& other ) noexcept;(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <chrono>

void func(std::string str)
{
    std::cout << str << " " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

void func1(std::string str)
{
    std::cout << str << " " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
}

int main()
{
    std::thread t1(func,"t1");
    std::cout << "t1_ID = " << t1.get_id() << std::endl;
    std::thread t2(func1,"t2");
    std::cout << "t2_ID = " << t2.get_id() << std::endl;
    t1.swap(t2);
    std::cout << "t1_ID = " << t1.get_id() << std::endl;
    std::cout << "t2_ID = " << t2.get_id() << std::endl;
    t1.join();
    t2.join();
    return 0;
}
2)执行结果

在这里插入图片描述

参考资料:[ [std::thread - C++中文 - API参考文档 ] ]( std::thread - C++中文 - API参考文档 (apiref.com) )
如有谬误,请各位大佬指正。

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

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

相关文章

滚动表格(vue版本)【已验证可正常运行】

演示图 注&#xff1a;以下代码来自于GPT4o&#xff1a;国内官方直连GPT4o 代码 <template><div><div class"alarmList-child" ref"alarmList" mouseenter.stop"autoRoll(1)" mouseleave.stop"autoRoll()"><div…

相机光学(二十四)——CRA角度

CRA角度 0.参考资料1.什么是CRA角度2.为什么 CRA 会导致luma shading3.为什么 CRA 会导致color shading4.CRA相差过大的具体表现5.CRA Matching6.怎样选择sensor的CRA 0.参考资料 1.芯片CRA角度与镜头的匹配关系&#xff08;一&#xff09;   2.芯片CRA角度与镜头选型的匹配关…

记录一次麒麟V10 安装sysbench各种报错(关于MySQL)处理过程

sysbench手工下载&#xff1a; https://github.com/akopytov/sysbench 下载.zip文件&#xff0c;上传到服务器上 解压、安装&#xff1a; unzip sysbench-master.zipcd sysbench-master/sh autogen.sh./configure 报错&#xff1a;没有mysql驱动 configure: error: mysql_c…

MySQL数据库-Windows部署MySQL环境

Windows部署MySQL环境​​​​​​ 一、下载mysql数据库 进入MySQL官方网站&#xff08;MySQL :: MySQL DownloadsMySQL&#xff09;&#xff0c;随后按如下红框方式操作&#xff1a; ​ ​ ​ ​ 这里选择的是离线安装&#xff0c;第一个是在线安装 下载好安装包后开始…

iPad手写笔哪款比较好?2024五款爆火iPad电容笔推荐!新手必看!

在iPad等触控设备日益普及的今天&#xff0c;手写笔作为提升生产力和创意表达的重要工具&#xff0c;正受到越来越多用户的青睐。然而&#xff0c;随着市场需求的激增&#xff0c;市面上电容笔品牌与型号繁多&#xff0c;跟风购买往往容易遭遇“踩雷”情况。因此&#xff0c;作…

【Linux】查找命令——which,type,find,whereis,locate

命令与文件的查找 文件的查找可就厉害了&#xff0c;因为我们常常需要知道哪个文件放在哪里&#xff0c;才能够对该文件进行一些修改或维护等操作。 有时候某些软件配置文件的文件名是不变的&#xff0c;但是各Linux发行版放置的目录则不同。 此时就要利用一些查找命令将该配…

iPad电容笔什么牌子好?2024最值得买的五款高性价比电容笔推荐!

现在平板和电容笔在一定程度上可以替代传统的笔和纸&#xff0c;不仅减少纸张浪费&#xff0c;还可以导入教材和习题册。只需携带它们就无需携带厚重的书本&#xff0c;这种环保、便捷、方便的特点吸引了越来越多的用户。但电容笔品牌的不断涌现&#xff0c;也让用户更加难以抉…

Wormhole Filters: Caching Your Hash on Persistent Memory——泛读笔记

EuroSys 2024 Paper 论文阅读笔记整理 问题 近似成员关系查询&#xff08;AMQ&#xff09;数据结构可以高效地近似确定元素是否在集合中&#xff0c;例如Bloom滤波器[10]、cuckoo滤波器[23]、quotient滤波器[8]及其变体。但AMQ数据结构的内存消耗随着数据规模的增长而快速增长…

管易云和金蝶云星空单据接口对接

管易云和金蝶云星空单据接口对接 数据源系统:金蝶云星空 金蝶K/3Cloud在总结百万家客户管理最佳实践的基础上&#xff0c;提供了标准的管理模式&#xff1b;通过标准的业务架构&#xff1a;多会计准则、多币别、多地点、多组织、多税制应用框架等&#xff0c;有效支持企业的运营…

400G SR4和800G SR8光模块在AI集群中的应用

人工智能&#xff08;AI&#xff09;技术的快速发展下&#xff0c;AI集群的计算能力和数据传输需求不断提升。为了满足这一需求&#xff0c;光模块技术也在不断进步。高速率光模块作为新一代高速光通信解决方案&#xff0c;正在逐步应用于AI集群中&#xff0c;为其提供更高效、…

【带你全面了解 RAG,深入探讨其核心范式、关键技术及未来趋势】

文末有福利&#xff01; 大型语言模型&#xff08;LLMs&#xff09;已经成为我们生活和工作的一部分&#xff0c;它们以惊人的多功能性和智能化改变了我们与信息的互动方式。 然而&#xff0c;尽管它们的能力令人印象深刻&#xff0c;但它们并非无懈可击。这些模型可能会产生…

google::protobuf命名空间下常用的C++ API----message.h

#include <google/protobuf/message.h> namespace google::protobuf 假设您有一个消息定义为: message Foo {optional string text 1;repeated int32 numbers 2; } 然后&#xff0c;如果你使用 protocol编译器从上面的定义生成一个类&#xff0c;你可以这样使用它: …

[C++][设计模式][访问器]详细讲解

目录 1.动机2.模式定义3.要点总结4.代码感受1.代码一2.代码二 1.动机 在软件构件过程中&#xff0c;由于需求的变化&#xff0c;某些类层次结构中常常需要增加新的行为(方法)&#xff0c;如果直接在基类中做这样的更改&#xff0c; 将会给子类带来很繁重的变更负担&#xff0c…

快手矩阵管理系统:开启短视频营销的智能时代

在短视频内容营销的浪潮中&#xff0c;快手矩阵管理系统以其独特的优势和功能&#xff0c;成为品牌和个人创作者不可或缺的工具。本文将详细解析快手矩阵管理系统的核心功能&#xff0c;探讨它如何帮助用户高效管理多平台、多账号的内容发布和互动。 快手矩阵管理系统概述 快…

【Java EE】Spring IOCDI

Spring IOC & DI 文章目录 Spring IOC & DI一、Spring是什么&#xff1f;二、IOC(控制反转)2.1 通俗理解2.2 造汽车的例子理解IOC2.3 IOC详解1. 获取Bean2. 方法注解——Bean1. 应用场景&#xff1a;2. 应用方法&#xff1a;3. 注意要点&#xff1a; 特别注意: 四、DI4…

Superset超火的企业级可视化BI分析工具

Superset&#xff0c;听起来就像是超级集合&#xff0c;确实&#xff0c;它几乎集合了所有你需要的数据功能。简单说&#xff0c;它就是一个现代化、功能强大的数据可视化工具。 它支持各种数据库&#xff0c;有着丰富的可视化选项&#xff0c;可以用来创建漂亮的数据仪表盘&a…

【数据清洗中分段线性插值法原理】

数据清洗中分段线性插值法原理 一、什么是分段线性插值法&#xff1f;二、分段线性插值法的数学原理三、分段线性插值法的应用步骤1. 引入库2. 创建示例数据3. 应用分段线性插值法4. 可视化插值结果 一、什么是分段线性插值法&#xff1f; 分段线性插值法通过在已知数据点之间…

【C语言】return 关键字

在C语言中&#xff0c;return是一个关键字&#xff0c;用于从函数中返回值或者结束函数的执行。它是函数的重要组成部分&#xff0c;负责将函数的计算结果返回给调用者&#xff0c;并可以提前终止函数的执行。 主要用途和原理&#xff1a; 返回值给调用者&#xff1a; 当函数执…

[leetcode hot 150]第一百一十七题,填充每个节点的下一个右侧节点

题目&#xff1a; 给定一个二叉树&#xff1a; struct Node {int val;Node *left;Node *right;Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL 。 初始状态下&#x…

【图卷积网络】GCN基础原理简单python实现

基础原理讲解 应用路径 卷积网络最经典的就是CNN&#xff0c;其 可以提取图片中的有效信息&#xff0c;而生活中存在大量拓扑结构的数据。图卷积网络主要特点就是在于其输入数据是图结构数据&#xff0c;即 G ( V , E ) G(V,E) G(V,E)&#xff0c;其中V是节点&#xff0c;E是…