C++11并发技术

thread与std::async

C++ 11 增加了对线程的基本支持,其使用方式与其他语言的线程写法几乎一样,也就是定义需要跑的函数,然后开启多个线程,线程内部提供同步的数据结构。一个标准的线程写法如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <thread>
//This function will be called from a thread
void call_from_thread() {
std::cout << "Hello, World" << std::endl;
}

int main() {
//Launch a thread
std::thread t1(call_from_thread);
//Join the thread with the main thread
t1.join();
return 0;
}

C++11除了线程外,还提供了一个更高阶抽象的std::async, 如果没有其他的要求,最好使用std::async这样的方法,而不是裸的线程,这是因为async可以获得返回的结果。
总结而言,C++11新引入的并发元素有: 任务、期值、线程、互斥量条件变量和原子对象等一套。

thread_local

线程一个重要的概念就是线程的局部变量,因为局部变量的创建与普通的C++变量创建时机是不一样的,仅在线程使用变量时才会创建,且每个线程创建一次。部分内容可以参考:
http://cifangyiquan.net/programming/thread_local/.我们看以下例子来了解下thread_local这一关键字的重要作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <thread>
//This function will be called from a thread
class A{
public:
int data=0;
void p(int i){
data += i;
std::cout << data << std::endl;
}
};
thread_local A a;

void call_from_thread(A& a, int i) {
a.p(i);
}

int main() {
//Launch a thread
std::thread t1(call_from_thread, std::ref(a), 1);
std::thread t2(call_from_thread, std::ref(a), 3);
//Join the thread with the main thread
t1.join();
t2.join();
return 0;
}
// 输出结果
// 3
// 4

稍微改变一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <thread>
//This function will be called from a thread
class A{
public:
int data=0;
void p(int i){
data += i;
std::cout << data << std::endl;
}
};
thread_local A a;

void call_from_thread(int i) {
a.p(i);
}

int main() {
//Launch a thread
std::thread t1(call_from_thread, 1);
std::thread t2(call_from_thread, 3);
//Join the thread with the main thread
t1.join();
t2.join();
return 0;
}
// 输出结果
// 1
// 3

为什么呢?这是因为第一种通过ref调用的方式,a是在主线程创建并传递到子线程的,而第二种方式,则是在线程创建时,每个线程创建时才创建的a。为了展示这一过程,我们将构造函数和析构函数打印出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <thread>
#include <mutex>
//This function will be called from a thread
std::mutex cout_mutex;

class A{
public:
int data=0;
A(){
cout_mutex.lock();
std::cout << "ID: " << std::this_thread::get_id() << "Object A Constructed" << std::endl;
cout_mutex.unlock();
}
~A(){
cout_mutex.lock();
std::cout << "ID: " << std::this_thread::get_id() << "Object A Destroyed" << std::endl;
cout_mutex.unlock();
}
void p(int i){
data += i;
std::cout << data << std::endl;
}
};
thread_local A a;

void call_from_thread(int i) {
std::cout << "ID: " << std::this_thread::get_id() << " Thread created" << std::endl;
a.p(i);
}

int main() {
//Launch a thread
std::thread t1(call_from_thread, 1);
std::thread t2(call_from_thread, 3);
//Join the thread with the main thread
t1.join();
t2.join();
return 0;
}
// 输出结果
ID: 140123813201664 Thread created
ID: 140123813201664Object A Constructed
3
ID: 140123813201664Object A Destroyed
ID: 140123821594368 Thread created
ID: 140123821594368Object A Constructed
1
ID: 140123821594368Object A Destroyed

0%