前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Cpp(七) std::thread 标准库多线程

Cpp(七) std::thread 标准库多线程

作者头像
Autooooooo
发布于 2020-11-09 02:42:55
发布于 2020-11-09 02:42:55
86200
代码可运行
举报
文章被收录于专栏:CoxhuangCoxhuang
运行总次数:0
代码可运行

C++ 多线程

#1 环境

代码语言:javascript
代码运行次数:0
运行
复制
C++14
CMake 3.17
macOS 10.15.5
Clion

#2 开始

#2.1 不使用线程

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <thread>

void func1(){
    std::cout << "func1" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 休眠
}
void func2(){
    std::cout << "func2" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 休眠
}

int main() {
    std::cout << "Hello, Thread!" << std::endl;
    func1();
    func2();
    return 0;
}

现象:

先打印输出func1两秒后再打印输出func2,再过两秒后退出程序

#2.2 使用多线程

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <thread>

void func1(){
    std::cout << "func1" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 休眠
}
void func2(){
    std::cout << "func2" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 休眠
}

int main() {
    std::cout << "Hello, Thread!" << std::endl;
    std::thread t1(func1);
    std::thread t2(func2);
    t1.join();
    t2.join();
    return 0;
}

现象:

几乎同时打印输出func1 func2, 两秒后退出程序

#3 std::thread 接口

#3.1 std::thread t1(func1)

  • std::thread: 变量类型
  • t1: 多线程变量名
  • func1: 需要执行的方法

#3.2 t1.join();

连接

代码语言:javascript
代码运行次数:0
运行
复制
std::thread t1(func1);
t1.join();
  • join(): 阻塞等func1执行完毕后返回

#3.3 t1.detach();

分离

代码语言:javascript
代码运行次数:0
运行
复制
std::thread t1(func1);
t1.detach();
  • detach(): 不阻塞,直接返回

#3.4 get_id()

获取线程id

代码语言:javascript
代码运行次数:0
运行
复制
std::thread t1(func1);
std::thread::id t1_id = t1.get_id();
std::cout << "t1 id:" << t1_id << std::endl;

#3.5 swap()

交换两个线程对象所代表的底层句柄(underlying handles)。

代码语言:javascript
代码运行次数:0
运行
复制
std::thread t1(func1);
std::thread t2(func2);
std::cout << "t1 id:" << t1.get_id() << std::endl;
std::cout << "t2 id:" << t2.get_id()<< std::endl;
std::swap(t1, t2);
std::cout << "t1 id:" << t1.get_id() << std::endl;
std::cout << "t2 id:" << t2.get_id()<< std::endl;
t1.join();
t2.join();
代码语言:javascript
代码运行次数:0
运行
复制
# output
Hello, Thread!
t1 id:0x7000069c8000
t2 id:0x700006a4b000
t1 id:0x700006a4b000
t2 id:0x7000069c8000
func1
func2

#3.6 mutex()

mutex是用来保证线程同步的,防止不同的线程同时操作同一个共享数据。

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <thread>
#include <mutex>

int count = 10;
std::mutex lock;

void func1(){
    while (count>0){
        lock.lock();
        count--;
        std::cout << count << std::endl;
        lock.unlock();
    }
}
void func2(){
    while (count>0){
        lock.lock();
        count--;
        std::cout << count << std::endl;
        lock.unlock();
    }
}

int main() {
    std::thread t1(func1);
    std::thread t2(func2);
    t1.join();
    t2.join();
    return 0;
}
代码语言:javascript
代码运行次数:0
运行
复制
# output
9
8
7
6
5
4
3
2
1
0
-1

但是使用mutex是不安全的,当一个线程在解锁之前异常退出了,那么其它被阻塞的线程就无法继续下去。

#3.7 lock_guard

使用lock_guard则相对安全,它是基于作用域的,能够自解锁,当该对象创建时,它会像m.lock()一样获得互斥锁,当生命周期结束时,它会自动析构(unlock),不会因为某个线程异常退出而影响其他线程

代码语言:javascript
代码运行次数:0
运行
复制
...
while (count>0){
    std::lock_guard<std::mutex> lk(lock);
    count--;
    std::cout << count << std::endl;
}
...

#4 线程池

线程的创建和销毁会消耗系统资源,为了避免系统的消耗,加入线程池概念,为的就是创建的线程存到队列中,线程执行结束后,不销毁,等到下一个申请线程时,从队列中取出已有的线程

这里使用GitHub上已经写好的第三方线程池库

GItHub地址: https://github.com/progschj/ThreadPool

代码语言:javascript
代码运行次数:0
运行
复制
#include <iostream>
#include <thread>
#include <mutex>
#include "ThreadPool.h"

void func1(){
    std::cout << "func1: " << std::this_thread::get_id() << " :func1"  << std::endl; // 打印当前线程id
    std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 休眠
}
void func2(){
    std::cout << "func2: " << std::this_thread::get_id() << " :func2" << std::endl; // 打印当前线程id 
    std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 休眠

}

int main() {
    ThreadPool pool(4); // 线程池最大线程数为4 
    pool.enqueue(func1);
    pool.enqueue(func1);
    pool.enqueue(func2);
    pool.enqueue(func2);
    pool.enqueue(func2); // 创建5个线程, 只要有两个线程的id相同,就能证明线程池可用
    return 0;
}
代码语言:javascript
代码运行次数:0
运行
复制
# output
func1: func1: func2: 0x700002a07000 :func20x700002901000 :func1
func2: 0x700002984000 :func1
0x700002a8a000 :func2
func2: 0x700002901000 :func2

有两个线程的id为0x700002901000,证明线程池可用

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/10/30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
UNIX(多线程):03--- 认识std::thread
std::thread 在 <thread> 头文件中声明,因此使用 std::thread 需包含 <thread> 头文件。
用户3479834
2021/02/03
8850
c++11多线程入门教程(一)
原文链接:https://www.cnblogs.com/DOMLX/p/10914162.html
徐飞机
2019/05/24
2.2K0
c++11 多线程入门教程(一)
原文链接:https://www.cnblogs.com/DOMLX/p/10945309.html
徐飞机
2019/06/03
9720
C++基础 多线程笔记(二)
程序运行结果依然是主线程和子线程各自输出1000条信息以及将信息保存到txt文件中,和上篇中 “死锁 & adopt_lock” 的结果类似,这里不再展示。
xxpcb
2020/08/04
5410
C++ 线程的使用
C++11 之前,C++ 语言没有对并发编程提供语言级别的支持,这使得我们在编写可移植的并发程序时,存在诸多的不便。现在 C++11 中增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线程程序的可移植性得到了很大的提高。
C语言与CPP编程
2021/10/09
9280
C++ 多线程 —— 锁
并发编程中经常需要考虑并发资源竞争读写的问题,因为多个流程同时修改、读取同一个资源时往往会发生超出预期的奇怪行为,因此我们的原则是并发执行任务但是资源读取的过程是清楚干净的。
为为为什么
2023/03/24
1.5K0
C++11-lambda表达式/包装器/线程库
捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用
用户9645905
2022/11/30
1.2K0
C++11-lambda表达式/包装器/线程库
C++多线程编程:深入剖析std::thread的使用方法
 是 C++11 中引入的一个库,用于实现多线程编程。它允许程序创建和管理线程,从而实现并发执行。
Lion Long
2025/01/04
5820
C++多线程编程:深入剖析std::thread的使用方法
【Example】C++ 标准库 std::thread 与 std::mutex
与 Unix 下的 thread 不同的是,C++ 标准库当中的 std::thread 功能更加简单,可以支持跨平台特性。
芯片烤电池
2022/04/27
1.2K0
C++多线程/原子性操作互斥锁
在C++11之前,涉及到多线程问题,都是和平台相关的,比如windows和linux下各有自己的接口,这使得代码的可移植性比较差。C++11中最重要的特性就是对线程进行支持了,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。要使用标准库中的线程,必须包含< thread >头文件。
二肥是只大懒蓝猫
2023/04/08
1.3K0
C++多线程/原子性操作互斥锁
C++11中的互斥锁讲解
我们现在有一个需求,我们需要对 g_exceptions 这个 vector 的访问进行同步处理,确保同一时刻只有一个线程能向它插入新的元素。为此我使用了一个 mutex 和一个锁(lock)。mutex 是同步操作的主体,在 C++ 11 的 <mutex> 头文件中,有四种风格的实现:
泽霖
2023/11/26
3430
线程同步-The Boost C++ Libraries
The Boost C++ Libraries 本博客是Synchronizing Threads的一篇译文。关于《The Boost C++ Llibraries》一书的在线完整书的目录,参见The Boost C++ Libraries,Boost库的官网地址是:https://www.boost.org/,翻译这篇博文时Boost库的最新版本是1.73.0
ccf19881030
2020/05/18
8820
C++:thread | condition_variable|mutex
相信大家在Linux系统编程中都接触过线程创建和退出的相关系统调用,这些系统调用是Linux环境下的一套线程设计方案。但是这种设计方案仅限于Linux环境下使用,其缺点就是可移植性差。所以C++设计了thread库,该库可以适用于任何平台下,从根本上解决了可移植性差的问题。
破晓的历程
2024/10/10
1290
C/C++开发基础——原子操作与多线程编程
因为,thread类的构造函数是一个可变参数模板,可接收任意数目的参数,其中第一个参数是线程对应的函数名称。
Coder-ZZ
2023/11/13
5870
C/C++开发基础——原子操作与多线程编程
C++11多线程编程(八)——死锁问题
看到“死锁”二字,你是不是慌得不知所措。死锁,顾名思义就是这个锁死掉了,再也动不了了。那死锁是怎么产生的呢?当你对某个资源上锁后,却迟迟没有释放或者根本就无法释放,导致别的线程无法获得该资源的访问权限,进而程序无法运行下去,有点像是阻塞的现象。但是阻塞是一种正常现象,而死锁可以说是一种bug,必须要处理。
一点sir
2024/01/10
2260
C++多线程编程和同步机制:详解和实例演示
在C++中,使用<thread>库来创建和管理线程。线程可以通过函数、成员函数或者Lambda表达式来实现。以下是一个使用Lambda表达式来创建线程的例子:
小万哥
2023/05/05
4710
C++多线程编程和同步机制:详解和实例演示
【C++】C++11的新特性 — 线程库 ,原子操作 , 条件变量
在Linux中我们了解了什么是线程: 【Linux】从零开始认识多线程 — 线程概念与底层实现 【Linux】从零开始认识多线程 — 线程控制 【Linux】从零开始认识多线程 — 线程ID 【Linux】从零开始认识多线程 — 线程互斥
叫我龙翔
2024/08/13
3490
【C++】C++11的新特性 — 线程库 ,原子操作 , 条件变量
【C++】C++11之线程库
在 C++11 之前,涉及到多线程问题,都是和平台相关的,比如 windows 和 linux 下各有自己的接 口,这使得代码的可移植性比较差 。 C++11 中最重要的特性就是对线程进行支持了,使得 C++ 在 并行编程时不需要依赖第三方库 ,而且在原子操作中还引入了原子类的概念。要使用标准库中的线程,必须包含< thread > 头文件。
青衫哥
2023/10/17
5030
【C++】C++11之线程库
std future get_waitkey(0)
1.1 关于std::future_status: std::future_status是一个枚举类型,其值有三:
全栈程序员站长
2022/10/04
4130
学习C++,必须学习的线程知识点
std::thread 是 C++ 标准库中提供的用于创建和管理线程的类。通过 std::thread,可以方便地创建新线程,并在其中执行指定的函数或可调用对象。
Linux兵工厂
2024/04/01
3540
学习C++,必须学习的线程知识点
相关推荐
UNIX(多线程):03--- 认识std::thread
更多 >
目录
  • C++ 多线程
    • #1 环境
    • #2 开始
      • #2.1 不使用线程
      • #2.2 使用多线程
    • #3 std::thread 接口
      • #3.1 std::thread t1(func1)
      • #3.2 t1.join();
      • #3.3 t1.detach();
      • #3.4 get_id()
      • #3.5 swap()
      • #3.6 mutex()
      • #3.7 lock_guard
    • #4 线程池
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档