目录
[├── 06_consumer.h](#├── 06_consumer.h)
[├── 06_consumer.cc](#├── 06_consumer.cc)
[├── 06_product.h](#├── 06_product.h)
[├── 06_product.cc](#├── 06_product.cc)
[├── 06_taskqueue.h](#├── 06_taskqueue.h)
[├── 06_taskqueue.cc](#├── 06_taskqueue.cc)
[└── 06_text.cc](#└── 06_text.cc)
作业:使用C++11的线程、互斥锁、条件变量实现生产者消费者代码
01_example.cc
cpp
#include <iostream>
using std::cout;
using std::endl;
//值语义,对象语义
class NonCopyable{
protected:
NonCopyable()=default;
NonCopyable(const NonCopyable &n)=delete;
NonCopyable & operator=(const NonCopyable & n)=delete;
~NonCopyable()=default;
};
class Example
:NonCopyable
//03 将基类的拷贝构造,赋值私有
{
public:
Example()=default;
//02 删除 拷贝构造,赋值
Example(const Example & e)=delete;
Example & operator=(const Example & e)=delete;
private:
//01 私有 拷贝构造,赋值
/* Example(const Example & e); */
/* Example & operator=(const Example & e); */
};
void test(){
Example ex1;
/* Example ex2=ex1; */
Example ex3;
/* ex3=ex1; */
}
int main(void)
{
test();
return 0;
}
/*
从前面的知识,我们知道,基类的拷贝构造函数和operator=运算符函数
不能被派生类继承,那么在执行派生类对象间的复制操作时,
就需要注意以下几种情况:
1.如果用户定义了基类的拷贝构造函数,而没有定义派生类的拷贝构造函数,
那么在用一个派生类对象初始化新的派生类对象时,两对象间的派生类部分
执行缺省的行为,而两对象间的基类部分执行用户定义的基类拷贝构造丽数。
2.如果用户重载了基类的赋值运算符函数,而没有重载派生类的赋值运算符
函数,那么在用一个派生类对象给另一个已经存在的派生类对象赋值时,两
对象间的派生类部分执行缺省的赋值行为,而两对象间的基类部分执行用户
定义的重载赋值函数。
3.如果用户定义了派生类的拷贝构造函数或者重载了派生类的对象赋值运算
符=,则在用已有派生类对象初始化新的派生类对象时,或者在派生类对象
间赋值时,将会执行用户定义的派生类的拷贝构造函数或者重载赋值函数,
而不会再自动调用基类的拷贝构造函数和基类的重载对象赋值运算符,这时,
通常需要用户在派生类的拷贝构造函数或者派生类的赋值函数中显式调用基
类的拷贝构造或赋值运算符函数。
*/
02_thread.cc
cpp
#include <iostream>
#include <thread>
#include <functional>
using std::cout;
using std::endl;
using std::bind;
using std::thread;
using std::function;
void threadFunc(int x){
cout<<x<<" void threadFunc(int )"<<endl;
cout<<x<<" child thread id"<<std::this_thread::get_id()<<endl;
//2 std:this_thread namespace
}
class Example{
public:
void operator()(int x){
cout<<x<<"- Example::void threadFunc(int )"<<endl;
cout<<x<<"- Example::child thread id"<<std::this_thread::get_id()<<endl;
}
};
int main(int argc,char** argv)
{
cout<<"_________main thread id"<<std::this_thread::get_id()<<endl;
//主线程没有对象
//创建线程对象,启动线程入口函数
thread th(threadFunc,1);
cout<<"1_________child thread id"<<th.get_id()<<endl;
//1 成员函数调用
//---------------------------------------------//
//传递函数指针
typedef void(*pFunc)(int);
pFunc f =threadFunc;
thread th2(f,2);
cout<<"2_________child thread id"<<th2.get_id()<<endl;
//---------------------------------------------//
//传递函数引用&
typedef void(&ppFunc)(int);
ppFunc f1 =threadFunc;//& must 初始化
thread th3(f1,3);
cout<<"3_________child thread id"<<th3.get_id()<<endl;
//---------------------------------------------//
//传递函数对象
Example ex;
thread th4(ex,4);
cout<<"4_________child thread id"<<th4.get_id()<<endl;
//---------------------------------------------//
//传递lambda
thread th5([](int x)->void{
cout<<x<<"- void threadFunc(int )"<<endl;
cout<<x<<"- child thread id"<<std::this_thread::get_id()<<endl;
},5);
cout<<"5_________child thread id"<<th5.get_id()<<endl;
//---------------------------------------------//
//传递function
using namespace std::placeholders;
function<void(int)> f6=bind(threadFunc,_1);
thread th6(f6,6);
cout<<"6_________child thread id"<<th6.get_id()<<endl;
//---------------------------------------------//
//传递bind's return
thread th7(bind(threadFunc,7));
cout<<"7_________child thread id"<<th7.get_id()<<endl;
th.join();
/* th.join();//double join段错误 //invalid aegument */
th2.join();
th3.join();
th4.join();// no wait ::terminate called without an active exception
th5.join();
th6.join();
th7.join();
//wait child thread
//main可能先跑完,再跑两个线程,可能交叉反正不确定
/* cout<<endl; */
return 0;
}
03_mutex.cc
cpp
#include <iostream>
#include <thread>
#include <mutex>
using std::cout;
using std::endl;
using std::thread;
using std::mutex;
int gCnt=0;
mutex mtx;//全局唯一的一把锁
//use RAII 的思想,栈对象的生命周期进行资源管理
//对象离开作用域,自动执行析构函数
class MutexLockGuard{
public:
MutexLockGuard(mutex &mutx)
:_mx(mutx)//delete construct(&)
{
_mx.lock();
}
MutexLockGuard(const MutexLockGuard & m)=delete;
MutexLockGuard & operator=(const MutexLockGuard & m)=delete;
~MutexLockGuard(){
_mx.unlock();
}
private:
mutex & _mx;//delete construct(&)
};
void threadFunc(){
/* mtx.lock(); */
for(size_t i=0;i!=10000;++i){
/* mtx.lock(); */
{//块作用域,局部上锁
MutexLockGuard autoLock(mtx);
++gCnt;
}
/* mtx.unlock(); */
}
/* mtx.unlock(); */
}
int main(void)
{
thread th0(threadFunc);
thread th1(threadFunc);
th0.join();
th1.join();
cout<<gCnt<<endl;
return 0;
}
04_unique_mutex.cc
cpp
#include <iostream>
#include <thread>
#include <mutex>
using std::cout;
using std::endl;
using std::thread;
using std::mutex;
using std::lock_guard;
using std::unique_lock;
int gCnt=0;
mutex mtx;//全局唯一的一把锁
void threadFunc(){
for(size_t i=0;i!=10000;++i){
/* MutexLockGuard autoLock(mtx); */
/* lock_guard<mutex> lg(mtx); */
//效果更高
unique_lock<mutex> ul(mtx);
++gCnt;
ul.unlock();//lock(),unlock(),更加灵活
}
}
int main(void)
{
thread th0(threadFunc);
thread th1(threadFunc);
th0.join();
th1.join();
cout<<gCnt<<endl;
return 0;
}
05_atomic.cc
cpp
#include <iostream>
#include <thread>
#include <atomic>
using std::cout;
using std::endl;
using std::thread;
using std::atomic;
/* int gCnt=0; */
atomic<int> gCnt(0);//原子数据类型,涉及硬件层面
//内置,自定义类型的指针,
//is_lock_free
void threadFunc(){
for(size_t i=0;i!=10000;++i){
++gCnt;
}
}
int main(void)
{
thread th0(threadFunc);
thread th1(threadFunc);
th0.join();
th1.join();
cout<<gCnt<<endl;
return 0;
}
├── 06_consumer.h
cpp
#ifndef __CONSUMER_H__
#define __CONSUMER_H__
class TaskQueue;//前向声明
class Consumer
{
public:
Consumer();
~Consumer();
void consumer(TaskQueue & TaskQueue);
private:
/* TaskQueue _taskQueue; */
//只要是子对象,必须要头文件,其他可以前向声明一下
};
#endif
├── 06_consumer.cc
cpp
#include "06_consumer.h"
#include "06_taskqueue.h"
#include <iostream>
#include <thread>
using std::cout;
using std::endl;
Consumer::Consumer(){
}
Consumer::~Consumer(){
}
//produce data
void Consumer::consumer(TaskQueue & TaskQueue){
int cnt=20;
while(cnt--){
int number=TaskQueue.pop();
cout<<"<<<producer consumer num:"<<number<<endl;
//thread sleep
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
├── 06_product.h
cpp
#ifndef __PRODUCT_H__
#define __PRODUCT_H__
class TaskQueue;//前向声明
class Product
{
public:
Product();
~Product();
void produce(TaskQueue & TaskQueue);
private:
/* TaskQueue _taskQueue; */
//只要是子对象,必须要头文件,其他可以前向声明一下
};
#endif
├── 06_product.cc
cpp
include "06_product.h"
#include "06_taskqueue.h"
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <thread>
//自定义 C C++
using std::cout;
using std::endl;
Product::Product(){
}
Product::~Product(){
}
//produce data
void Product::produce(TaskQueue & TaskQueue){
srand(clock());//返回处理时间的近似值
//clock_t clock(); ::srand(::clock())匿名空间
int cnt=20;
while(cnt--){
int number=rand()%100;
TaskQueue.push(number);//produce
cout<<">>producer produce num:"<<number<<endl;
//thread sleep
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
├── 06_taskqueue.h
cpp
xiaohuichen@xiaohuichen-virtual-machine:~/001/913$ cat 06_taskqueue.h
#ifndef __TASKQUEUE_H__
#define __TASKQUEUE_H__
#include <queue>
#include <mutex>
#include <condition_variable>
using std::queue;
using std::mutex;
using std::unique_lock;
using std::condition_variable;
//wait notify_one notify_all
class TaskQueue
{
public:
TaskQueue(size_t capa);
~TaskQueue();
//生产消费数据
void push(const int & value);
int pop();
bool empty()const ;
bool full()const ;
private:
size_t _capacity; //任务队列的大小
queue<int> _que; //存放数据的数据结构
mutex _mutex; //互斥锁
condition_variable _notFull; //非满条件变量
condition_variable _notEmpty; //非空条件变量
};
#endif
├── 06_taskqueue.cc
cpp
#include "06_taskqueue.h"
TaskQueue::TaskQueue(size_t capa)
:_capacity(capa)
,_que()
,_mutex()
,_notFull()
,_notEmpty()
{}
TaskQueue::~TaskQueue(){
}
//生产数据
void TaskQueue::push(const int & value){
//上锁··判满··解锁
// full:prodect(sleep),notfull:product(wake)
unique_lock<mutex> u1(_mutex);
if(full()){
_notFull.wait(u1);
// 线程在条件变量 _notFull 上等待,直到队列不满
}
_que.push(value);
_notEmpty.notify_one();
// 唤醒一个等待在 _notEmpty 条件变量上的线程
}
//消费数据
int TaskQueue::pop(){
//上锁··判empty··解锁
// empty:custor(sleep),not:custor(wake)
unique_lock<mutex> u1(_mutex);
if(empty()){
_notEmpty.wait(u1);
}
int temp=_que.front();
_que.pop();
_notFull.notify_one();
return temp;
}
bool TaskQueue::empty()const{
return _que.size()==0;
}
bool TaskQueue::full()const{
return _que.size()==_capacity;
}
└── 06_text.cc
cpp
#include "06_product.h"
#include "06_consumer.h"
#include "06_taskqueue.h"
#include <iostream>
#include <thread>
using std::cout;
using std::endl;
using std::thread;
void test(){
TaskQueue taskQue(10);
Product pr;
Consumer co;
thread pro(&Product::produce,&pr,std::ref(taskQue));//传引用
thread con(&Consumer::consumer,&co,std::ref(taskQue));
pro.join();
con.join();
}
int main(void)
{
test();
return 0;
}
作业:使用C++11的线程、互斥锁、条件变量实现生产者消费者代码
06_all