并发与并行
并发
并发(Concurrence):指两个或两个以上的事件或活动在同一时间间隔内发生。并发的实质是单个物理 CPU(也可以多个物理CPU) 在若干道程序之间多路复用,并发可以对有限物理资源强制行使多用户共享以提高效率。
逻辑上来说,执行实例是并发执行,但是物理上仍是串行执行
并行
并行(Parallelism)指两个或两个以上事件或活动在同一时刻发生。在多道程序环境下,并行性使多个程序同一时刻可在不同CPU上同时执行
C++ 并行
C++11 新标准中引入了五个头文件来支持多线程编程,它们分别是 <atomic>, <thread>, <mutex>, <condition_variable>
和 <future>
一个简单的例子:
#include <bits/stdc++.h>
#include <thread>
using namespace std;
int e = 0;
void f() {
e++;
cout << "e is " << e << endl;
}
int main() {
for (int i = 0; i < 20; i++) {
std::thread t(f);
t.join();
}
return 0;
}
一个新的线程通过构建 std::thread 对象而启动
#include <bits/stdc++.h>
#include <thread>
#include <vector>
using namespace std;
int e = 0;
bool finished = false;
void f() {
e++;
cout << "test " << e << endl;
}
int main() {
vector<thread> v;
for (int i = 0; i < 20; i++) {
v.emplace_back(f);
}
for (auto& it:v)
it.join();
return 0;
}
新线程启动后,起始线程继续执行,如果起始线程不等待新线程结束,就会执行到main最后。可能新线程根本没机会启动,例子中用join让主线程等待新线程
join
加入一个新线程,主线程等待新线程结束
只要调用过join,线程就不可再汇合(joinable)
detach
不需要等待线程结束,将其分离,无法等待新线程完结
线程在后台运行,无法直接通信。然而分离的线程确实仍在后台运行,其归属权和控制权交给了C++运行时库,一旦线程退出,与之关联的资源都会被正确回收
在thread中传递参数
传递参数的方式很简单,直接向std::thread的构造函数增添更多参数即可
注意:thread的构造函数原样复制所提供的值,并没有转换为预期的参数类型引用的传参
所以要传引用的时候,应该显式地使用std::ref
void update(int &data) //expects a reference to int
{
data = 15;
}
int main()
{
int data = 10;
// This doesn't compile as the data value is copied when its reference is expected.
//std::thread t1(update, data);
std::thread t1(update, std::ref(data)); // works
t1.join();
return 0;
}
类似的例子还有string:
#include <bits/stdc++.h>
#include <thread>
#include <vector>
using namespace std;
void f(string const &s) {
cout << "s = " << s << endl;
}
int main() {
std::thread t(f, string("test"));
t.join();
return 0;
}
右值引用:C++11中增加了右值引用,右值引用关联到右值时,右值被存储到特定位置,右值引用指向该特定位置,也就是说,右值虽然无法获取地址,但是右值引用是可以获取地址的,该地址表示临时对象的存储位置
C++ 标准规定,临时对象只能绑定到 const
左值引用或右值引用,而不能绑定到非常量的左值引用