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

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

作者头像
Autooooooo
发布2020-11-09 10:42:55
8000
发布2020-11-09 10:42:55
举报
文章被收录于专栏:Coxhuang

C++ 多线程

#1 环境

代码语言:javascript
复制
C++14
CMake 3.17
macOS 10.15.5
Clion

#2 开始

#2.1 不使用线程

代码语言:javascript
复制
#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
复制
#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
复制
std::thread t1(func1);
t1.join();
  • join(): 阻塞等func1执行完毕后返回

#3.3 t1.detach();

分离

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

#3.4 get_id()

获取线程id

代码语言:javascript
复制
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
复制
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
复制
# output
Hello, Thread!
t1 id:0x7000069c8000
t2 id:0x700006a4b000
t1 id:0x700006a4b000
t2 id:0x7000069c8000
func1
func2

#3.6 mutex()

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

代码语言:javascript
复制
#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
复制
# output
9
8
7
6
5
4
3
2
1
0
-1

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

#3.7 lock_guard

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

代码语言:javascript
复制
...
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
复制
#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
复制
# 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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 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 归档