在C++ 11之前,官方并没有支持线程库。C++ 11通过标准库引入了对 thread 类的支持,大大方便了完成多线程开发的工作。

std::thread 构造函数 

(1)thread() noexcept;

(2)thread( thread&& other ) noexcept;

(3)template< class Function, class... Args >

explicit thread( Function&& f, Args&&... args );

(4)thread(const thread&) = delete;

(1) 构造新的 thread 对象,但由于没有传入函数,所以thread对象还没有关联到线程。

(2) 移动构造函数。构造表示曾为 other 所表示的执行线程的 thread 对象。此调用后 other 不再表示执行线程。

(3) 构造新的 std::thread 对象并将它与执行线程关联。新的执行线程开始执行。

(4) 复制构造函数被删除, thread 不可复制。

下面我们来看一段代码:

#include <iostream>

#include <utility>

#include <thread>

#include <chrono>

void f1(int n)

{

for (int i = 0; i < 5; ++i) {

std::cout << "Thread 1 executing\n";

++n;

std::this_thread::sleep_for(std::chrono::milliseconds(10));  //毫秒级

   // std::this_thread::sleep_for(std::chrono::seconds(1));  //秒级

}

}

void f2(int& n)

{

for (int i = 0; i < 5; ++i) {

std::cout << "Thread 2 executing\n";

++n;

std::this_thread::sleep_for(std::chrono::milliseconds(10));

}

}

class foo

{

public:

void bar()

{

for (int i = 0; i < 5; ++i) {

std::cout << "Thread 3 executing\n";

++n;

std::this_thread::sleep_for(std::chrono::milliseconds(10));

}

}

int n = 0;

};

class baz

{

public:

void operator()()

{

for (int i = 0; i < 5; ++i) {

std::cout << "Thread 4 executing\n";

++n;

std::this_thread::sleep_for(std::chrono::milliseconds(10));

}

}

int n = 0;

};

int main()

{

int n = 0;

foo f;

baz b;

std::thread t1; // t1 不是线程

std::thread t2(f1, n + 1); // 按值传递

std::thread t3(f2, std::ref(n)); // 按引用传递

std::thread t4(std::move(t3)); // t4 现在运行 f2() 。 t3 不再是线程

std::thread t5(&foo::bar, &f); // t5 在对象 f 上运行 foo::bar()

std::thread t6(std::ref(b)); // t6 在对象 b 上运行 baz::operator()

t2.join();

t4.join();

t5.join();

t6.join();

std::cout << "Final value of n is " << n << '\n';

std::cout << "Final value of foo::n is " << f.n << '\n';

std::cout << "Final value of baz::n is " << b.n << '\n';

}

注意:若需要传递引用参数给线程函数,则必须包装它 (例如用 std::ref 或 std::cref)。忽略来自函数的任何返回值。若函数抛异常,则调用 std::exception()。

观察器

joinable

bool joinable() const noexcept;

用于判断 thread 对象是否关联到某一线程,若 thread 对象与执行线程关联,则返回 true ,反之为 false 。

#include <iostream>

#include <thread>

#include <chrono>

void foo()

{

std::this_thread::sleep_for(std::chrono::seconds(1));

}

int main()

{

std::thread t;

std::cout << "before starting, joinable: " << std::boolalpha << t.joinable()

<< '\n';

t = std::thread(foo);

std::cout << "after starting, joinable: " << t.joinable()

<< '\n';

t.join();

std::cout << "after joining, joinable: " << t.joinable()

<< '\n';

}

输出信息:

before starting, joinable: false

after starting, joinable: true

after joining, joinable: false

操作

join

void join();

阻塞当前线程直至 *this 所标识的线程结束其执行。*this 所标识的线程的完成同步于对应的从 join() 成功返回。*this 自身上不进行同步。同时从多个线程在同一 thread 对象上调用 join() 构成数据竞争,导致未定义行为。

#include <iostream>

#include <thread>

#include <chrono>

void foo()

{

// 模拟昂贵操作

std::this_thread::sleep_for(std::chrono::seconds(1));

}

void bar()

{

// 模拟昂贵操作

std::this_thread::sleep_for(std::chrono::seconds(1));

}

int main()

{

std::cout << "starting first helper...\n";

std::thread helper1(foo);

std::cout << "starting second helper...\n";

std::thread helper2(bar);

std::cout << "waiting for helpers to finish..." << std::endl;

helper1.join();

helper2.join();

std::cout << "done!\n";

}

输出信息:

starting first helper...

starting second helper...

waiting for helpers to finish...

done!

get_id

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

返回标识与 *this 关联的线程的 std::thread::id 。

#include <iostream>

#include <thread>

#include <chrono>

void foo()

{

std::this_thread::sleep_for(std::chrono::seconds(1));

}

int main()

{

std::thread t1(foo);

std::thread::id t1_id = t1.get_id();

std::thread t2(foo);

std::thread::id t2_id = t2.get_id();

std::cout << "t1's id: " << t1_id << '\n';

std::cout << "t2's id: " << t2_id << '\n';

t1.join();

t2.join();

}

t1's id: 0x35a7210f

t2's id: 0x35a311c4

detach

void detach();

从 thread 对象分离执行线程,允许执行独立地持续。一旦该线程退出,则释放任何分配的资源。调用 detach 后 *this 不再占有任何线程。

#include <iostream>

#include <chrono>

#include <thread>

void independentThread()

{

std::cout << "Starting concurrent thread.\n";

std::this_thread::sleep_for(std::chrono::seconds(2));

std::cout << "Exiting concurrent thread.\n";

}

void threadCaller()

{

std::cout << "Starting thread caller.\n";

std::thread t(independentThread);

t.detach();

std::this_thread::sleep_for(std::chrono::seconds(1));

std::cout << "Exiting thread caller.\n";

}

int main()

{

threadCaller();

std::this_thread::sleep_for(std::chrono::seconds(5));

}

输出信息:

Starting thread caller.

Starting concurrent thread.

Exiting thread caller.

Exiting concurrent thread.

swap

void swap( std::thread& other ) noexcept;

交换二个 thread 对象的底层柄。

#include <iostream>

#include <thread>

#include <chrono>

void foo()

{

std::this_thread::sleep_for(std::chrono::seconds(1));

}

void bar()

{

std::this_thread::sleep_for(std::chrono::seconds(1));

}

int main()

{

std::thread t1(foo);

std::thread t2(bar);

std::cout << "thread 1 id: " << t1.get_id() << '\n'

<< "thread 2 id: " << t2.get_id() << '\n';

std::swap(t1, t2);

std::cout << "after std::swap(t1, t2):" << '\n'

<< "thread 1 id: " << t1.get_id() << '\n'

<< "thread 2 id: " << t2.get_id() << '\n';

t1.swap(t2);

std::cout << "after t1.swap(t2):" << '\n'

<< "thread 1 id: " << t1.get_id() << '\n'

<< "thread 2 id: " << t2.get_id() << '\n';

t1.join();

t2.join();

}

输出信息:

thread 1 id: 140185268262656

thread 2 id: 140185259869952

after std::swap(t1, t2):

thread 1 id: 140185259869952

thread 2 id: 140185268262656

after t1.swap(t2):

thread 1 id: 140185268262656

thread 2 id: 140185259869952

总结:

(0x01) std::thread 类创建线程非常方便,构造 thread 对象时传入一个需要运行的函数及其参数。构造完成后,新的线程马上被创建,同时执行该对象。注意:若需要传递引用参数给线程函数,则必须包装它(例如用 std::ref 或 std::cref)。

(0x02) 使用 std::thread 默认的构造函数构造对象时,该对象是不关联任何线程的。可以在之后的使用过程中再关联到某一线程。可以通过使用 joinable() 接口,判断一个 thread 对象是否关联某个线程。

(0x03) 关联到线程的 thread 对象析构前,必须调用 join() 接口等待线程结束。或者 thread 对象调用 detach() 接口解除与线程的关联,否则会抛异常。

(0x04) thread 对象 detach() 后会独立执行直至结束,而对应的 thread 对象变成不关联任何线程的对象,joinable() 将返回 false。

(0x05) std::thread 没有拷贝构造函数和拷贝赋值操作符,因此不支持复制操作(但从构造函数的示例代码可以看出 std::thread 可以 move )。这也说明了没有两个 thread 对象可以表示同一执行线程。

C++ 多线程 std::thread 使用总结的更多相关文章

  1. C++11多线程std::thread的简单使用

    在cocos2dx 2.0时代,我们使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上.但在cocos2dx 3.0中并未发现有pthread的支持文件,原来c++11中已经拥有 ...

  2. C++11并发——多线程std::thread (一)

    https://www.cnblogs.com/haippy/p/3284540.html 与 C++11 多线程相关的头文件 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是< ...

  3. Cocos2dx 3.0 过渡篇(二十七)C++11多线程std::thread的简单使用(下)

    本篇接上篇继续讲:上篇传送门:http://blog.csdn.net/star530/article/details/24186783 简单的东西我都说的几乎相同了,想挖点深的差点把自己给填进去. ...

  4. C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语 ...

  5. Cocos2dx 3.0 过渡篇(二十六)C++11多线程std::thread的简单使用(上)

    昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:"看到前面那俩教练没?老色鬼两枚!整天调戏女学员."她说:"还好啦,这毕竟是他们的乐趣所在,你不认为教练每 ...

  6. C++11多线程std::thread创建方式

    //#include <cstdlib> //#include <cstdio> //#include <cstring> #include <string& ...

  7. C++11 多线程编程 使用lambda创建std::thread (生产/消费者模式)

    要写个tcp server / client的博客,想着先写个c++11多线程程序.方便后面写博客使用. 目前c++11中写多线程已经很方便了,不用再像之前的pthread_create,c++11中 ...

  8. c++ 如何获取多线程的返回值?(std::thread ,std::async)

    //简单的 c++11 线程,简单方便,成员函数随便调用,非成员函数也一样,如需要获取返回时,请自行使用条件变量 std::thread run([&](){ //执行一些耗时的操作 retu ...

  9. c++11多线程记录1 -- std::thread

    启动一个线程 话不多说,直接上代码 void func(); int main() { std::thread t(func); //这里就开始启动线程了 t.join(); // 必须调用join或 ...

随机推荐

  1. 集群数据ID生成之美团叶子生成

    转自https://tech.meituan.com/2017/04/21/mt-leaf.html 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在美团点评的金融.支付.餐饮.酒店. ...

  2. archaius(2) 配置源

    上一节讲到,archaius实现动态配置的核心就是定时去配置中心拉去配置内容,接下来几接就来看一下archaius内部具体是如何实现的. 首先我们来了解一下配置源,什么是配置源呢,archaius内部 ...

  3. .NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书

    简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...

  4. JVM学习(九)volatile应用

    一.初认volatile 首先学习volatile关键字时,我们先简单的了解一下它能干啥: 工作内存与主内存同步延迟现象导致的可见性问题: 可通过synchronized或volatile关键字解决, ...

  5. 从 LRU Cache 带你看面试的本质

    前言 大家好,这里是<齐姐聊算法>系列之 LRU 问题. 在讲这道题之前,我想先聊聊「技术面试究竟是在考什么」这个问题. 技术面试究竟在考什么 在人人都知道刷题的今天,面试官也都知道大家会 ...

  6. 深入解析Vue里函数的调用顺序介绍

    今天为大家分享一篇对vue里函数的调用顺序介绍,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. method用来定义方法的,比如你@click=& ...

  7. Laravel Event的分析和使用

    Laravel Event的分析和使用 第一部分 概念解释 请自行查看观察者模式 第二部分 源码分析 (逻辑较长,不喜欢追代码可以直接看使用部分) 第三部分 使用 第一部分 解释 当一个用户阅读了一篇 ...

  8. 041 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 03 案例演示while循环的使用——求1到5的累加和

    041 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 03 案例演示while循环的使用--求1到5的累加和 本文知识点:案例演示while循环的使用1 ...

  9. Python基本数据类型详细介绍

    Python提供的基本数据类型主要有:布尔类型.整型.浮点型.字符串.列表.元组.集合.字典等等 1.空(None)表示该值是一个空对象,空值是Python里一个特殊的值,用None表示.None不能 ...

  10. python文档下载

    网址记录:https://docs.python.org/3.6/