C++ 多线程 std::thread 使用总结
在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 使用总结的更多相关文章
- C++11多线程std::thread的简单使用
在cocos2dx 2.0时代,我们使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上.但在cocos2dx 3.0中并未发现有pthread的支持文件,原来c++11中已经拥有 ...
- C++11并发——多线程std::thread (一)
https://www.cnblogs.com/haippy/p/3284540.html 与 C++11 多线程相关的头文件 C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是< ...
- Cocos2dx 3.0 过渡篇(二十七)C++11多线程std::thread的简单使用(下)
本篇接上篇继续讲:上篇传送门:http://blog.csdn.net/star530/article/details/24186783 简单的东西我都说的几乎相同了,想挖点深的差点把自己给填进去. ...
- C++11并发编程:多线程std::thread
一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语 ...
- Cocos2dx 3.0 过渡篇(二十六)C++11多线程std::thread的简单使用(上)
昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:"看到前面那俩教练没?老色鬼两枚!整天调戏女学员."她说:"还好啦,这毕竟是他们的乐趣所在,你不认为教练每 ...
- C++11多线程std::thread创建方式
//#include <cstdlib> //#include <cstdio> //#include <cstring> #include <string& ...
- C++11 多线程编程 使用lambda创建std::thread (生产/消费者模式)
要写个tcp server / client的博客,想着先写个c++11多线程程序.方便后面写博客使用. 目前c++11中写多线程已经很方便了,不用再像之前的pthread_create,c++11中 ...
- c++ 如何获取多线程的返回值?(std::thread ,std::async)
//简单的 c++11 线程,简单方便,成员函数随便调用,非成员函数也一样,如需要获取返回时,请自行使用条件变量 std::thread run([&](){ //执行一些耗时的操作 retu ...
- c++11多线程记录1 -- std::thread
启动一个线程 话不多说,直接上代码 void func(); int main() { std::thread t(func); //这里就开始启动线程了 t.join(); // 必须调用join或 ...
随机推荐
- SpringBoot中使用切面的每次传的参数,进行解析,验签,并返回解码后的参数
目的,在每次请求的时候,对每次传的参数,进行解析,验签,并返回解码后的参数, 以json传递: 例子背景: IOT平台提供对外可访问的接口, 需要对所有参数的传递做到 不泄露.认证的目的:所以需要在每 ...
- java虚拟机5 字节码
java字节码本质是java程序的格式化表示,便于机器处理.所以他是java程序的另一种表示,java程序包含的信息他都包含并且更加结构化. java虚拟机字节码格式: magic 魔数,标识该文件是 ...
- IDEA—使用插件反编译jar包
关注微信公众号:CodingTechWork,一起学习进步. 引言 在产品上线后,如果遇到问题阻塞,我们第一步要做的就是去查看日志,但是代码不是一个人写的,说不定就会遇到没有日志的,遇到这种情况, ...
- Sublime Text3 for Java 编译运行环境配置 入门详解 - 精简归纳
Sublime Text3 for Java 编译运行环境配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 9 / 24 转载请注明出处!️ 目录 Sublime Text3 for ...
- 在移动硬盘上安装Linux Mint19记录
前要: 有一12年买的手提电脑,打算在其上直接装linux部署分布式爬虫顺便学linux 唔,开机吧--然开机动画没有,只有间断有序的悲鸣,一查,主板逝世 卖给收买旧电脑估计不到20-不能忍,想了想不 ...
- SpringBoot中pom引入gson异常
在pom中引入gson依赖,启动spring boot项目中报错 Description:An attempt was made to call the method com.google.gson. ...
- P3378 堆(模板)
P3378 [模板]堆 题目描述 给定一个数列,初始为空,请支持下面三种操作: 给定一个整数 x,请将 x 加入到数列中. 输出数列中最小的数. 删除数列中最小的数(如果有多个数最小,只删除 1 个) ...
- matlab中drawnow更新图窗并处理回调
来源:https://ww2.mathworks.cn/help/matlab/ref/drawnow.html?searchHighlight=drawnow&s_tid=doc_srcht ...
- Java (三)APACHE Commons IO 常规操作
上一篇:Java (二)基于Eclipse配置Commons IO的环境 例1:查看文件.文件夹的长度(大小). 1 import java.io.File; 2 3 import org.apach ...
- 【题解】 P2734 [USACO3.3]游戏 A Game
\(\color{purple}{Link}\) \(\text{Solution:}\) 考虑区间\([l,r]\)的最优解.显然它可以由\([l+1,r]\)或\([l,r-1]\)转移而来.至此 ...