C++并发编程 一
对于并发编程,首先应该从线程说起,对于线程的基本概念就不多说了,有不清楚的同学可以查查相关资料。这里就从< thread>开始看起,先对C++11的线程有个大致了解。
std::thread
一个thread对象也许没有表示任何线程,比如在默认构造后、move from后、detach、join后;一个在运行的线程也不一定有与之关联的thread对象,比如在detach后。不会出现两个thread对象表示着同一个执行的线程,于是thread是不可拷贝构造和拷贝赋值的,但是可以移动构造和移动赋值。
Hello World
std::thread的用法与pthread的类似,先从一个简单的例子看起:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <iostream>
#include <thread>
int main(int argc, char** argv) {
std::thread t{
[](){
std::cout << "Hello World!" << std::endl;
}
}
t.join();
return 0;
}
这里使用clang来编译,注意要加上 -std=c++11
1 |
|
这段代码里使用一个打印hello world的lambda表达式作为参数构造一个thread(当然,传递一个函数(指针)也是没有问题的),然后调用join()等待线程运行完毕。
成员函数
- 构造函数
1 |
|
1) 创建了一个thread对象,没有表示任何线程
2) 移动构造函数。创建一个表示other表示的线程的thread对象,构造完成后other不在表示之前的线程了
3) 创建一个表示一个运行线程的thread对象。首先,构造函数通过使用下面的函数拷贝/移动所有的参数(连同函数f和它的参数一起)到线程可以访问的存储区:
1 |
|
需要注意的是在此期间抛出的所有异常都会抛在当前线程,而不是新创建的线程里。
下面来看下新的线程将会怎么去处理传入的参数。我们设value_args(包含函数和它参数一起的参数)为t1,t2,…tN,N为sizeof…(value_args),value_args是通过调用上面的decay_copy得到的。然后会按照下面的规则来执行代码:
1) 如果f是类T的成员函数的指针,就会执行f,会忽略掉返回值。代码实际上是这样执行的:
1 |
|
2) 如果N == 1,f是一个类的成员数据对象(member data object),则它会被访问。但是这个对象的值会被忽略。代码实际上是这样执行的:
1 |
|
3) 否则的话,f会被当做一个非成员函数来调用,返回值会被忽略。代码实际上是这样执行的:
1 |
|
4) 拷贝构造函数是delete的,线程是不可拷贝的。没有两个thread对象表示着同一个线程。
- Observers
1 |
|
- Operations
1 |
|
namespace this_thread
1 |
|