文章图片
文章目录
-
- 前言
- 观察者模式
- 观察者模式案例(线程池)
- 观察者模式的优势
- 注意事项
前言 【我用过的设计模式|我用过的设计模式(3)-- 观察者模式】关于设计模式,这次我要一改常态,我就挑重要的讲。那些碎碎的就算了。
观察者模式 说到观察者模式,那自然是离不开线程了。
什么是观察者模式呢?顾名思义,是一种触发机制。在电视里见过埋手雷不?某个倒霉蛋不小心扯到了手雷的线,轰的一声儿手雷炸了,倒霉蛋瞬间连渣都没得了。
这就是观察者模式,其中要素有:监视者、消息传递、响应者。
那根线就是监视者,消息传递方式为线拉动了手雷的保险栓,响应者为手雷,轰的一声就是它的响应。
观察者模式案例(线程池) 这段代码后面还看得到,因为享元模式的一个很经典的案例也是线程池。。。
//Pthread_pool.h#pragma once#include #include
#include //据说list不安全,不安全就不安全吧,更不安全的都忍了
#include "Cond.h" //封装过的条件变量类,继承自封装的mutex锁类,所以具有锁和条件变量的双重属性using namespace std;
class Task //任务接口,每个任务必须实现的接口,以供工作线程调度任务的执行
{public:
Task() {
}
virtual ~Task() {
}
virtual int run() = 0;
//留给子类实现
};
typedef list list_task;
//任务队列,用于暂存等待处理的任务,等待线程唤醒时处理,提供一种缓冲机制。class Pthread_Pool //线程池类
{public:
Pthread_Pool(unsigned int max = 100, unsigned int min = 10, unsigned int wait = 60);
~Pthread_Pool();
void addTask(Task* task);
// 往任务队列中添加新线程private:
static void* taskThread(void* arg);
// 工作线程
void createThread();
// 新建一个线程
void destroyThread();
// 销毁一个线程池unsigned int maxcount;
// 最大线程数
unsigned int mincount;
// 最小线程数
unsigned int count;
// 当前线程池中线程数
unsigned int waitcount;
// 等待线程数
unsigned int waitsec;
// 等待时间
list_tasktaskList;
//任务队列
Cond taskCond;
//任务锁,线程接任务时使用
Cond cond;
//线程锁,创建线程时使用
bool Stop;
//线程池是否被允许运作,初始化线程池对象时置0,线程池销毁时置为1
};
#include "Pthread_Pool.h"//开放接口1
Pthread_Pool::Pthread_Pool(unsigned int max, unsigned int min, unsigned int wait)
{//配置基本参数
count = 0;
//当前线程池为空
waitcount = 0;
//没有等待线程
mincount = min;
//核心线程数(出厂配置)
maxcount = max;
//最大线程数(能承受的最高配置)
waitsec = wait;
//线程保活时长(过了时长还没接到任务,那就裁掉)
Stop = false;
//允许运作//上锁,创建一定数量的线程作为初始线程池
cond.lock();
for (unsigned i = 0;
i < mincount;
i++)
{createThread();
//跳转到这个函数的实现->->->->->
}
cond.unlock();
}Pthread_Pool::~Pthread_Pool()
{destroyThread();
//销毁线程池
}void Pthread_Pool::createThread()
{pthread_t tid;
int ret = pthread_create(&tid, NULL, taskThread, (void*)this);
//以执行taskThread()为目的创建线程,跳转到taskThread()函数的实现 ->->->->->if (ret < 0)
perror("pthread create error");
else
count++;
}// 工作线程
void* Pthread_Pool::taskThread(void* arg)
{pthread_detach(pthread_self());
//设置线程自分离属性
Pthread_Pool* pool = (Pthread_Pool*)arg;
while (1)
{pool->cond.lock();
//如果没有工作线程在等待
if (pool->taskList.empty())
{if (pool->Stop) //当收到线程池停止运行的消息时
{pool->count--;
//线程数减一
pool->cond.unlock();
pthread_exit(NULL);
//本线程强制退出
}pool->waitcount++;
//等待任务的线程数加一
bool bSignal = pool->cond.timewait(pool->waitsec);
//新任务等待被唤醒
pool->waitcount--;
//没等到,没事干,喝西北风了// 删除无用线程
if (!bSignal && pool->count > pool->mincount) //如果没事干 && 有多余线程
{pool->count--;
//先裁员一个,不要一次做绝了,反正是在while循环里面,没事干裁员机会多得是
pool->cond.unlock();
pthread_exit(NULL);
}
}
pool->cond.unlock();
//记得要释放锁//如果有工作线程在等待
if (!pool->taskList.empty())
{pool->taskCond.lock();
//上任务锁
Task* t = pool->taskList.front();
//获取任务队列中最前端的任务并执行
pool->taskList.pop_front();
//移除被领取的任务
pool->taskCond.unlock();
//记得解锁t->run();
//任务开始
delete t;
//弄完就删了
}
}
pthread_exit(NULL);
}//开放接口2,向任务队列中添加任务
void Pthread_Pool::addTask(Task* task)
{if (Stop) //线程池是否停止工作
return;
//向任务队列中添加新任务
taskCond.lock();
//上任务锁
taskList.push_back(task);
//添加任务
taskCond.unlock();
//记得解锁cond.lock();
//上线程锁
if (waitcount) //如果有空闲线程
{cond.signal();
//唤醒一个线程
}
else if (count < maxcount) //如果没有空闲线程,一般来说,走到这里面来,那这个线程池的设计是有点失败了
{createThread();
//那就创建一个
cond.signal();
//然后唤醒
}
cond.unlock();
}void Pthread_Pool::destroyThread()
{printf("destroy?\n");
#if 0//强行清理
list_task::iterator it = taskList.begin();
for (;
it!= taskList.end();
it++)
{Task* t = *it;
delete t;
t = NULL;
}
taskList.clear();
#endif// 等待所有线程执行完毕
Stop = true;
while (count > 0)
{cond.lock();
cond.broadcast();
//广播
cond.unlock();
sleep(1);
}
}
这里面还配置了保证线程同步的锁,而观察者模式的唤醒,即采用条件变量来唤醒,一旦有任务的到来,会判断是否有空余线程,如果有,就直接唤醒一个去处理,如果没有,就会加入到任务队列中去。
观察者模式的优势
- 观察者和被观察者之间是抽象耦合的,如此设计,不论是观察者还是被观察者,都可以独立拓展。
- 建立了一套触发机制。
- 广播链问题
如果一个对象,它既是观察者,又是被观察者,那就比较复杂了,我是还没遇到那种特别变态的广播链了,简单点的单行广播链还是可以应付的(每条链都是三个对象,用”中介+观察“就可以解决)。
推荐阅读
- QT|基于C++的Qt(一)概述
- Java系列——多线程实战|关于Java并发编程的总结和思考
- 并发|Java并发编程的总结和思考
- #|Java多线程那些事,对Java并发编程2w余字的总结,超详细(从入门到完全掌握)
- web并发|多线程并发、死锁
- vscode配置|vscode配置c++可能遇到的俩问题(头文件找不到和找不到编译的文件)
- yxc|AcWing 寒假每日一题 2021-01-19 找硬币
- c++高级技巧|QT打造高效线程池异步QWebSocket 客户端
- C++|C/C++ 实现的websocket客户端