c++11线程库

1.线程的创建

1
2
3
template< class F, class... Args >
explicit thread( F&& f, Args&&... args );
//&&用到了引用折叠

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
}

int main(){
thread td(threadFunc,1);
//和bind类似 bind(threadFunc,1)
return 0;
}
//可能运行会失败, 子线程可能还没有运行 主线程就已经结束了

使用join函数让主线程等待子线程运行结束

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
}

int main(){
thread td(threadFunc,1);
//和bind类似 bind(threadFunc,1)
th.join();
return 0;
}

2.线程ID

1
2
std::thread::id get_id() noexcept;
//但是平时使用的时候可以使用std::this_thread::get_id()获取线程id

获取线程id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
cout <<"child thread id = "<< std::this_thread::get_id() << endl;
}

int main(){
cout <<"main thread id = "<< std::this_thread::get_id() << endl;
thread td(threadFunc,1);
//和bind类似 bind(threadFunc,1)
th.join();
return 0;
}

也可以通过对象调用成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
cout <<"child thread id = "<< std::this_thread::get_id() << endl;
}

int main(){
cout <<"main thread id = "<< std::this_thread::get_id() << endl;
thread td(threadFunc,1);
cout <<"child thread id = "<< td.get_id() << endl;//获取子线程的线程id
//和bind类似 bind(threadFunc,1)
th.join();
return 0;
}

3.线程的入口函数

1.传递普通函数

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
}

int main(){
thread td(threadFunc,1);
//和bind类似 bind(threadFunc,1)
th.join();
return 0;
}

2.传递函数指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
}

int main{
typedef void(*pFunc)(int);
using pFunc = void(*)(int);

pFunc f = threadFunc;
thread th(f,2);
th.join();


return 0;
}

3.传递函数引用(了解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <thread>

void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
}

int main{
typedef void(&pFunc)(int);
using pFunc = void(&)(int);

pFunc f = threadFunc;
thread th(f,2);
th.join();


return 0;
}

4.传递函数对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <thread>
class Func{
public:
void operator()(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;

}
};


int main{
Func pfunc;
thread th(pFunc,2);
th.join();


return 0;
}

5.lambda表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main{

thread th([](int x,int y){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
cout << "y =" << y << endl;
},2,3);


th.join();


return 0;
}

6.传递function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main{
Funct;ion<void(int)> f = [](int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
cout << "y =" << y << endl;
};
thread th(f,2);//传递的是function类型的函数对象


th.join();


return 0;
}

7.用bind绑定函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void threadFunc(int x){
cout << "void thraedFunc(int)" << endl;
cout << "X = " << x << endl;
}

int main{


function<void()> f = bind(threadFunc,7);


thread th(f,2);//传递的是function类型的函数对象
//或者
thread th(bind(threadFunc,7));

th.join();


return 0;
}

互斥锁

1.头文件

1
#include <mutex>

2.锁的使用

不加锁会有问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <mutex>
#incldue <thread>

int global = 0;
void threadFunc(){
for(size_t i = 0; i < 1000000; ++i){
++gobal;
}
}

int mian(){
trhead th1(threadFunc);
thread th2(threadfunc);

th1.join();
th2.join();


cout << "global = " << global << endl;

return 0;
}

加锁

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
#include <mutex>
#incldue <thread>

int global = 0;
mutex mtx;
void threadFunc(){
for(size_t i = 0; i < 1000000; ++i){
mtx.lock();
++global;//对共享资源进行写操作的时候要上锁
mtx.unlock();
}
}

int mian(){
trhead th1(threadFunc);
thread th2(threadfunc);

th1.join();
th2.join();


cout << "global = " << global << endl;

return 0;
}

如果上锁了,但是忘记解锁呢?

会导致死锁,如何解决?

可以利用栈对象的生命周期管理,类似于智能指针,RAII机制

1
2
3
4
5
6
7
8
9
10
11
12
13
class MutexLockGuard{
public:
MutexLockGuard(int &mtx)
:_mutex(mtx)
{
_mutex.lock();
}
~MutexLockGuard(){
_mutex.unlock();
}
private:
mutex &_mutex;
};

lock_guard于unique_lock

lock_guard

构造函数

1
2
3
explicit lock_guard( mutex_type& m );
lock_guard( mutex_type& m, std::adopt_lock_t t );
lock_guard( const lock_guard& ) = delete;

lock_guard的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <mutex>
#incldue <thread>

int global = 0;
mutex mtx;
void threadFunc(){
for(size_t i = 0; i < 1000000; ++i){
lock_guard<mutex> lg(mtx);//会自动上锁和解锁
++global;
}
}

int mian(){
trhead th1(threadFunc);
thread th2(threadfunc);

th1.join();
th2.join();


cout << "global = " << global << endl;

return 0;
}

lock_guard原理于上述MutexLockGuard一致

1
2
3
4
5
6
7
8
9
10
11
12
13
class MutexLockGuard{
public:
MutexLockGuard(int &mtx)
:_mutex(mtx)
{
_mutex.lock();
}
~MutexLockGuard(){
_mutex.unlock();
}
private:
mutex &_mutex;
};

缺陷:

  • 释放(解锁)的时机太固定了,只能在作用域内的代码执行完之后才会被释放,(锁的粒度太大了)(也就是锁的范围)

为了解决这个问题,又引入了unique_lock

unique_lock

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unique_lock() noexcept;
unique_lock( unique_lock&& other ) noexcept;

explicit unique_lock( mutex_type& m );

unique_lock( mutex_type& m, std::defer_lock_t t ) noexcept;

unique_lock( mutex_type& m, std::try_to_lock_t t );

unique_lock( mutex_type& m, std::adopt_lock_t t );

template< class Rep, class Period >
unique_lock( mutex_type& m,
const std::chrono::duration<Rep, Period>& timeout_duration );

template< class Clock, class Duration >
unique_lock( mutex_type& m,
const std::chrono::time_point<Clock, Duration>& timeout_time );

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <mutex>
#incldue <thread>

int global = 0;
mutex mtx;
void threadFunc(){
for(size_t i = 0; i < 1000000; ++i){
unique_lock<mutex> lg(mtx);//会自动上锁和解锁
++global;
}
}

int mian(){
trhead th1(threadFunc);
thread th2(threadfunc);

th1.join();
th2.join();


cout << "global = " << global << endl;

return 0;
}

与lock_gurad的区别

提供了lock,unlock成员函数也就是说,既可以自动解锁上锁也可以手动解锁

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
#include <mutex>
#incldue <thread>

int global = 0;
mutex mtx;
void threadFunc(){
for(size_t i = 0; i < 1000000; ++i){
unique_lock<mutex> ul(mtx);//会自动上锁和解锁

++global;
ul.unlock();//可以手动解锁,构造函数里自动的上锁
ul.lock();//可以手动上锁,析构函数里自动解锁
}
}

int mian(){
trhead th1(threadFunc);
thread th2(threadfunc);

th1.join();
th2.join();


cout << "global = " << global << endl;

return 0;
}

注意:lock_guard没有unique_lock灵活,因为unique_lock可以手动上锁与解锁,但是lock_guard的使用效率更高

可以不加锁也让读写共享资源的操作变成原子性的吗?

atomic可以把操作变成原子性的,底层使用了CAS机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#incldue <thread>
#include <atomic>
atomic<int>global(0);
mutex mtx;
void threadFunc(){
for(size_t i = 0; i < 1000000; ++i){
++global;//该操作不会被打断,所以不用进行加锁了

}
}

int mian(){
trhead th1(threadFunc);
thread th2(threadfunc);

th1.join();
th2.join();


cout << "global = " << global << endl;

return 0;
}

无锁的效率更高

CAS机制

有一个预期值和一个目标值,不停拿预期值与内存中的值进行比对,如果相等就把内存中的值改为目标值(因为是相等的,说明该值没有被其他线程修改),但是如果发现内存中额值与预期值是不等的,表明其他线程已经修改了该变量,所以本线程就不能进行修改。

条件变量condition

应用在生产者消费者模型中

生产者消费者模型

类图

pkRkrVJ.png

具体实现:

Prodect.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef PRODUCT
#define PRODUCT

class TaskQueue;


class Product
{
public:
void product(TaskQueue &);

};




#endif

Product.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "Product.hpp"
#include "TaskQueue.hpp"
#include <unistd.h>
#include <time.h>
#include <iostream>


void Product::product(TaskQueue & taskqueue){
::srand(::time(NULL));

for(int i = 0; i < 20; ++i){
int resultant = ::rand()%100;
taskqueue.push(resultant);
cout << "producer produce a procduct : " << resultant << endl;
sleep(1);
}
}


Consumer.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef CONSUMER
#define CONSUMER

class TaskQueue;

class Consumer
{
public:

void consumer(TaskQueue &);




};
#endif

Consumer.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Consumer.hpp"
#include "TaskQueue.hpp"
#include <iostream>
#include <unistd.h>


void Consumer::consumer(TaskQueue & taskqueue){
for(int i = 0; i < 20; ++i){
int product = taskqueue.pop();
cout << "consumer consume a product :" << product << endl;
sleep(1);
}
}

TaskQueue.hpp

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
#ifndef TASKQUEUE
#define TASKQUEUE

#include <queue>
#include <mutex>
#include <condition_variable>

using namespace std;

class TaskQueue
{
public:
TaskQueue(size_t queuesize);

void push(const int &value);

int pop();

bool isEmpty();

bool isFull();



private:
size_t _queueSize;
queue<int> _que;
mutex _mutex;
condition_variable _notEmpty;
condition_variable _notFull;
};


#endif

TaskQueue.cc

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
#include <iostream>
#include "TaskQueue.hpp"

TaskQueue::TaskQueue(size_t queuesize)
:_queueSize(queuesize)
,_que()
,_mutex()
,_notEmpty()
,_notFull()
{
}

void TaskQueue::push(const int &value){
unique_lock<mutex> ul(_mutex);
while(isFull()){
_notFull.wait(ul);
}
_que.push(value);
_notEmpty.notify_one();


}

int TaskQueue::pop(){

unique_lock<mutex> ul(_mutex);
while(isEmpty()){
_notEmpty.wait(ul);
}
int ret = _que.front();
_que.pop();
_notFull.notify_one();


return ret;
}

bool TaskQueue::isEmpty(){
return _que.size() == 0;
}

bool TaskQueue::isFull(){
return _que.size() == _queueSize;
}

test.cc

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 "Product.hpp"
#include "Consumer.hpp"
#include "TaskQueue.hpp"
#include <thread>

void test(){

Product pc;
Consumer cs;
TaskQueue tq(10);

thread pt(&Product::product,&pc,std::ref(tq));
thread ct(&Consumer::consumer,&cs,std::ref(tq));

pt.join();
ct.join();



}


int main()
{
test();
return 0;
}