开场白
以前写“桥接模式”的时候,说“桥接模式”是最抽象的设计模式,那是由于我没接触到“享元模式”。
可能桥接模式是最抽象的设计模式,可是享元模式我以为是最烦的设计模式了。前端
由于这个模式和==“池技术”有着密不可分==的联系。ios
享元模式与池技术
说到享元模式,第一个想到的应该就是池技术了,String常量池、数据库链接池、缓冲池等等都是享元模式的应用,因此说享元模式是池技术的重要实现方式。web
面向对象技术能够很好地解决一些灵活性或可扩展性问题,但在不少状况下须要在系统中增长类和对象的个数。当对象数量太多时,将致使运行代价太高,带来性能降低等问题。享元模式正是为解决这一类问题而诞生的。享元模式经过共享技术实现相同或类似对象的重用。数据库
享元模式定义与结构
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少许的对象,而这些对象都很类似,状态变化很小,能够实现对象的屡次复用。因为 享元模式要求可以共享的对象必须是细粒度对象,所以它又称为轻量级模式,它是一种 对象结构型模式。设计模式
线程池
内心没底,仍是先来个线程池压压惊吧。安全
//pthreadpool.h #pragma once #include <pthread.h> #include <unistd.h> #include <list> //听说list不安全,不安全就不安全吧,更不安全的都忍了 #include "Cond.h" //封装过的条件变量类,继承自封装的mutex锁类,因此具备锁和条件变量的双重属性 using namespace std; class Task //任务接口,每一个任务必须实现的接口,以供工做线程调度任务的执行 { public: Task() { } virtual ~Task() { } virtual int run() = 0; //留给子类实现 }; typedef list<Task*> 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_task taskList; //任务队列 Cond taskCond; //任务锁,线程接任务时使用 Cond cond; //线程锁,建立线程时使用 bool Stop; //线程池是否被容许运做,初始化线程池对象时置0,线程池销毁时置为1 };
//pthreadpool.cpp #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); } }
调用的地方是这样的:并发
class DoTask : public Task { public: DoTask(BtoC& send, PacketCommand1& packet); int run(); private: DB_command* task_db; BtoC* m_send; PacketCommand1 m_packet; PacketCommand3* f_packet; }; class BackServer { public: BackServer(char* IPnum); ~BackServer() { } int run(); private: PacketCommand1 m_packet; BtoC m_send; Pthread_Pool* m_pool; };
int BackServer::run() { int n = 0; while (1) { n = m_send.Read_date(m_packet.getData()); m_packet.setSize(n); DoTask* t = new DoTask(m_send, m_packet); m_pool->addTask(t); } return 0; }
在这个线程池中呢,能够看到负责建立线程和管理线程的函数(享元工厂)、每条线程的共用属性(外部属性)、传递给每一个线程的不一样任务(内部属性),还有负责缓冲的任务队列。
这些部分(享元工厂、元素外部属性、元素内部属性),就是享元模式的主要构成。ide
不过,在线程池调用的过程当中,确是存在了一个问题:DoTask* t = new DoTask(m_send, m_packet);这个可不见得回收了,要是等着系统的垃圾回收机制也是能够的,可是在高并发的状况下,这些尸位素餐的DoTask* t无疑成为了等待资源的任务们的“公敌”。svg
那么,今天我就来弄一个对象池,解决这个问题。函数
对象池类图
对象公有属性: (SignInfo)
DB_command* task_db; PacketCommand3* f_packet;
对象公有方法:
virtual int run(); virtual void setidentify(string identify); virtual string getidentify();
对象私有属性:(SignInfoPool)
BtoC* m_send; PacketCommand1 m_packet; string identify; //身份标识 int state; //是否处于空闲态
对象私有方法:
int run(); void setidentify(string identify); string getidentify();
享元工厂属性:
map<string,vector<SignInfo*>> mapSign; //hashmap不会用
享元工厂方法:
SignInfo* getSignInfo(string identify);
这样可好?
画个图看看:
接下来代码实现看看。
对象池代码实现
#include<iostream> #include<map> #include<vector> #include<string> using namespace std; class SignInfo { private: int db_task; //用int替代吧 int f_packet; public: virtual int run() = 0; virtual void setidentify(string identify) = 0; virtual string getidentify() = 0; virtual int isRun() = 0; }; class SignInfoPool : public SignInfo { private: string identify; int m_send; int m_packet; int state; //是否在使用 public: SignInfoPool() { this->state = 0; } //实例化对象时使用 void setInfo(int m_send, int m_packet) { this->m_send = m_send; this->m_packet = m_packet; }; //工厂生产的时候使用 void setidentify(string identify) { this->identify = identify; } string getidentify() { return this->getidentify(); } void setState(int state) { this->state = state; } int getState() { return this->state; } int isRun() { return this->state; } //在运行返回1.没运行返回0 int run() { cout << identify << " dosomething" << endl; } }; class SignInfoFactory { private: map<string, vector<SignInfo*>> mapSignInfo; int maxi; //最大对象数 int mini; //核心对象数 public: SignInfoFactory(int maxi,int mini) { this->maxi = maxi; this->mini = mini; createsigninfo("DBlogin"); //初始化一些用来处理登陆的对象 createsigninfo("DBregist"); //初始化一些用来处理注册的对象 createsigninfo("DBfpwd"); //初始化一些用来处理密码的对象 createsigninfo("DBfile"); //初始化一些用来处理文件的对象 } //初始化一些新对象 void createsigninfo(string identify) { vector<SignInfo*> temp; SignInfo* signinfo; for (int i = 0; i < mini; i++) { signinfo = new SignInfoPool(); signinfo->setidentify(identify); temp.push_back(signinfo); } mapSignInfo[identify] = temp; } SignInfo* getSignInfo(string identify) { int size = (mapSignInfo[identify]).size(); for (int i = 0; i < size; i++) { if (!(mapSignInfo[identify])[i]->isRun()) { return (mapSignInfo[identify])[i]; } } } void DestoryFactory() { //这。。。我也想知道怎么销毁。。。map没有迭代器啊。。。 } //结束时的工厂销毁 };
初次上手“享元模式”,多有纰漏,再写之时会整合成一个类,像线程池那样。
本文分享 CSDN - 看,将来。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。