这个具体的应用场景就是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即可。要达到一样的效果,有没有更好的实现,求高手指教。