深入了解C++(5)—— C++11 std::thread多线程编程

 按理来说学习多线程编程应该从深入浅的来学,但是由于学习的内容实在是有一些偏差,所以最后还是决定从stl标准库开始,学习C++多线程编程。

一 std::thread函数浅析

 相比pthread,C++11提供了一个调用非常简单的多线程库std::thread。std::thread的构造函数方便得出人意料,这得感谢std::bind这个神奇的函数。在std::thread的构造函数里,你可以直接传递一个函数和这个函数的参数列表给这个线程。你甚至可以传递一个类成员函数。如果你这么做了,参数列表的第二个参数(第一个参数是被传递的成员函数)会被作为该类成员函数所作用的实例。

1
2
3
4
5
6
7
8
9
10
// 假设buy是一个可调用的函数对象,它即可能是函数指针,也可能是函数对象
std::thread Annie(buy);
// Annie会去执行buy()
std::thread Bob(buy, book, food);
// Bob会去执行buy(book, food)

// 假设buy是Consumer的一个可调用的成员函数
Consumer Clara;
std::thread action(buy, Clara, phone);
// Clara会去执行Consumer.buy(phone)
1
2
pthread_create(&thread, &attr, f, static_cast<void *>(&args));
// 其中f是函数,args是所有参数打包成的结构体。因为pthread_create的第四个参数类型是void*,所以需要强制转型

 简单的mutex互斥锁实例

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
#include<iostream>
#include<thread>
#include<mutex>
std::mutex mut;
class A{
public:
volatile int temp;
A(){
temp=0;
}
void fun(int num){
int count=10;
while(count>0){
mut.lock();
temp++;
std::cout<<"thread_"<<num<<"...temp="<<temp<<std::endl;
mut.unlock();
count--;
}
}

void thread_run(){
std::thread t1(&A::fun,this,1);
std::thread t2(&A::fun,this,2);
t1.join();
t2.join();
}
};

int main(){
A a;
a.thread_run();
}

二 volatile 关键词

 在C++中使用volatile关键词可以防止编译器做出错误的优化。当一个线程对一个关键字进行多次读取时,编译器可能会把变量放入寄存器中,而不会每次都从内存中读取,这样如果变量在其他地方修改,会发生脏读取错误。

三 基于std::thread实现的生产者消费者模型。

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
50
#include <chrono>
#include <condition_variable>
#include <future>
#include <mutex>
#include <queue>

// 注意某些调用可能会抛出std::system_error,需要对其进行处理。
std::mutex mutex;
std::condition_variable condvar;

std::queue<int> msgQueue;

void producer(int start, int end){
for (int x = start; x < end; x++) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
{
std::lock_guard<std::mutex> guard(mutex);
msgQueue.push(x);
}
printf("Produce message %d\n", x);
condvar.notify_all();
}
}

void consumer(int demand){
while (true) {
std::unique_lock<std::mutex> ulock(mutex);
condvar.wait(ulock, []{ return msgQueue.size() > 0;});
// wait的第二个参数使得显式的double check不再必要
printf("Consume message %d\n", msgQueue.front());
msgQueue.pop();
--demand;
if (!demand) break;
}
}


int main(){
std::thread producer1(producer, 0, 10);
std::thread producer2(producer, 10, 20);
std::thread producer3(producer, 20, 30);
std::thread consumer1(consumer, 20);
std::thread consumer2(consumer, 10);

producer1.join();
producer2.join();
producer3.join();
consumer1.join();
consumer2.join();
}

 本文仅简单介绍std::thread的基本操作,更加复杂的操作以及更多的功能将在日后进一步研读。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×