这个具体的应用场景就是QQ的历史记录管理器里面。当你点击某个联系人时,有个工作线程会去数据库查询对应的聊天记录,一次点击对应一个查询任务。
1.当没有点击时,线程处于等待状态,一旦有点击,有查询任务,线程唤醒并执行任务。
2.在线程执行过程中,如果用户又多次点击,只需要执行最后一个点击产生的查询任务即可。
对应这个需求,我抽象出了一个多线程模型的实现。
OnlyRunNewestTask.h---------------------------begin--------------------------------
#pragma once
namespace ecs
{ namespace threadModal{class ECSUTIL_DllExport Task
{ public: virtual ~Task() {}
virtual void Run() = 0;
};class ECSUTIL_DllExport OnlyRunNewestTaskThread : public ctk::SimpleThread
{ public: OnlyRunNewestTaskThread() :ctk::SimpleThread(0, "OnlyRunNewestTaskThread") ,m_mtx() ,m_pTask(NULL) ,m_updated(false) ,m_break(false) { };virtual ~OnlyRunNewestTaskThread()
{ };void UpdateTask(Task* _data);
bool GetTask(Task** task); void Break();protected:
virtual void run();private:
typedef ctk::Monitor<ctk::Mutex> _Mutex;_Mutex m_mtx;
Task* m_pTask; bool m_updated; volatile bool m_break;};}
}OnlyRunNewestTask.h---------------------------end--------------------------------
OnlyRunNewestTask.cpp---------------------------begin--------------------------------
#include "ecsutil_prec.h"
#include "ecsutil/threadModal/OnlyRunNewestTask.h"using namespace ecs::threadModal;
void OnlyRunNewestTaskThread::UpdateTask(Task* _data)
{ _Mutex::Lock lck(m_mtx); delete m_pTask; m_pTask = _data; m_updated = true; m_mtx.notify();}bool OnlyRunNewestTaskThread::GetTask(Task** task)
{ _Mutex::Lock lck(m_mtx); if (!m_updated) { m_mtx.wait(); } if (m_updated) { *task = m_pTask; m_pTask = NULL; m_updated = false; return true; } return false;}void OnlyRunNewestTaskThread::Break()
{ m_break = true; UpdateTask(NULL);}void OnlyRunNewestTaskThread::run()
{ Task* taskData = NULL; while(GetTask(&taskData) && !m_break) { taskData->Run(); delete taskData; }}OnlyRunNewestTask.cpp---------------------------end--------------------------------
这种场景用这种解决方案是合适的。这个实现还有个缺点,在新任务来的时候,没有考虑中止执行旧任务。
Task在这里就是个空壳,作用是为了抽离出独立的多线程模型代码。外界要使用这个实现代码,只需要写个具体的任务类,然后继承Task即可。要达到一样的效果,有没有更好的实现,求高手指教。