关键词:并发 并行 C++11 多线程 Concurrency Action
0 写在前面
该文章素材来源于《C++ Concurrency in Action 2nd》一书,是我在阅读该书的笔记和练习。分享给大家,希望可以帮助C++开发者快速了解多线程。章节与原书类似,只保留关键概念与代码。以下内容均为个人理解,如有错误,参考原作。
1 概念与入门
1.1 什么是并发
简单来说就是同时进行。
1.2 多进程并发
并发分为线程并发与进程并发。
1.3 并发(concurrency)与并行(parallelism)
两者概念存在很大的重合,并行的关注在于同时进行,并发关注的是同时响应。
两个词汇来理解:并行计算,并发响应。
1.4 为什么使用并发
关注分离与执行分离。(在后面章节会详细解释这个内容)
1.5 并发与多线程
c++ 通过多线程实现并发。
1.6 开始编程
最简单的例子
#include <iostream>
#include <thread>
void hello()
{
std::cout << “hello,concurrent World\n”;
}
int main
{
std::thread t(hello);
t.join();
}
2 管理线程
2.1 发起一个线程
c的函数形式:
void a_thread_task(){};
std::thread my_thread(a_thread_task());
c++类的形式:(C++操作符重载)
class class_thread_task
{
public:
void operator()() const
{
do_something();
}
}
class_thread_task my_thread_task;
std::thread my_thread(my_thread_task);
补充:令人迷惑的C++:
无法正确编译
std::thread my_thread(class_thread_task());
正确的编译:
std::thread my_thread((class_thread_task()))
std::thread my_thread{class_thread_task()}
更简单的写法:(lambda表达式)
std::thread my_thread([]{do_something();do_something_else();});
补充:使用类中的某个方法作为线程的任务
class class_thread_task
{
public:
do_something();
}
class_thread_task my_thread_task;
std::thread my_thread(&class_thread_task::do_something,&my_thread_task);
等待一个线程执行结束
struct function
{
int& i;
function(int& _i):i(_i){};
void operator()()
{
for(unsigned j=0;j<10000;++j)
{
do_something(i);
}
}
}
void oops()
{
int i = 0;
function my_function(i);
std::thread my_thread(my_function);
my_thread.detach();
}
使用 detach() 将导致未定义的行为。
使用 join() 等待线程结束,使用joinable()可查询当前线程是否结束。
my_thread.join();
使用RAII形式来等待一个线程的结束(RAII:资源获取就是初始化)
class thread_guard
{
std::thread& t;
public:
explicit thread_guard(std::thread& t_):
t(t_)
{}
~thread_guard()
{
if(t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const&)=delete;
thread_guard& operator=(thread_guard const&)=delete;
};
struct function;
void f()
{
int i = 0;
function my_function(i);
std::thread t(mu_function);
thread_guard g(t);
other_things_but_not_immediately_return();
}
线程后台运行
std::thread t(do_something);
t=detach();
assert(!t.joinable());
2.2 向线程传递参数
附录
2022/10/10