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); 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); th.join(); return 0; }
|
2.线程ID
1 2
| std::thread::id get_id() noexcept;
|
获取线程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); 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; 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); 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); 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); thread th(bind(threadFunc,7)); th.join(); return 0; }
|
互斥锁
1.头文件
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
应用在生产者消费者模型中
生产者消费者模型
类图

具体实现:
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; }
|