Poco是一个强大的,用于构建C++程序的类库,它提供了许多非常好用的部件来帮助我们更快的开发C++应用程序,异步执行的相关部件正是这些好用的部件中的一部分。这里我们来看一下Poco库的异步执行组件的实现。
Poco库的异步执行组件主要有TaskManager,Task,ThreadPool等等。这里就主要从这些组件着手进行分析。
TaskManager/Task的使用
首先来看一下TaskManager/Task的使用。
1. 要使用Poco库的TaskManager来帮我们管理异步执行的任务,我们首先需要创建一个类,也是我们的任务的抽象,继承Poco的Task类,override其中的virtual函数virtual void runTask(),并在runTask()的实现中包含我们希望去异步执行的代码。
2. 然后创建一个线程池对象ThreadPool。这一步可选。
3. 创建一个TaskManager类的对象,并将前一步创建的线程池对象传给TaskManager的构造函数。TaskManager管理的所有Task都将在这个线程池的线程中执行。如果没有为TaskManager创建单独的线程池,则所有Task都将在default的线程池中执行。
4. 创建一个Task的对象。这个Task对象应该通过operator new,在堆上创建。
5. 通过前面创建的TaskManager对象,启动执行创建的Task。在Task执行完之后,TaskManager自己会把Task对象给delete掉。
具体还是来看一下代码比较方便:
#include <iostream>
#include <Poco/TaskManager.h>
#include <Poco/Task.h>
#include <Poco/TaskNotification.h>
#include <Poco/Thread.h>
#include <Poco/ThreadPool.h>
using namespace Poco;
using namespace std;
class DemoTask : public Task {
public:
DemoTask();
virtual ~DemoTask();
virtual void runTask();
};
DemoTask::DemoTask()
: Task("DemoTask") {
}
DemoTask::~DemoTask() {
}
void DemoTask::runTask() {
Thread::sleep(3000);
cout << "DemoTask runtask." << endl;
}
int main() {
ThreadPool threadPool(2, 32);
TaskManager taskManager(threadPool);
DemoTask * demoTask = new DemoTask;
taskManager.start(demoTask);
taskManager.joinAll();
cout << "Demo run end." << endl;
return 0;
}
这就是使用TaskManager/Task执行异步任务的基本方法了。但TaskManager提供的功能却不只如此,它还可以在Task的状态发生改变时,通过Observer通知我们具体的用法如下:
class TaskObserver {
public:
TaskObserver();
void handleTaskFinished(TaskStartedNotification *startedNotify);
void handleTaskCancelled(TaskCancelledNotification *cancelledNotify);
void handleTaskFinished(TaskFinishedNotification *completedNotify);
void handleTaskFailed(TaskFailedNotification *failedNotify);
void handleTaskProgressUpdated(TaskProgressNotification *progressNotify);
};
TaskObserver::TaskObserver() {
}
void TaskObserver::handleTaskFinished(TaskStartedNotification *startedNotify) {
startedNotify->release();
}
void TaskObserver::handleTaskCancelled(TaskCancelledNotification *cancelledNotify) {
cancelledNotify->release();
}
void TaskObserver::handleTaskFinished(TaskFinishedNotification *completedNotify) {
cout << "Task finished." << endl;
completedNotify->release();
}
void TaskObserver::handleTaskFailed(TaskFailedNotification *failedNotify) {
failedNotify->release();
}
void TaskObserver::handleTaskProgressUpdated(TaskProgressNotification *progressNotify) {
progressNotify->release();
}
int main() {
ThreadPool threadPool(2, 32);
TaskManager taskManager(threadPool);
TaskObserver observer;
Observer<TaskObserver, TaskFinishedNotification> finishedObserver(observer, &TaskObserver::handleTaskFinished);
taskManager.addObserver(finishedObserver);
DemoTask * demoTask = new DemoTask;
taskManager.start(demoTask);
在前面那个demo的基础之上,注册observer,并接收TaskManager关于task状态变化的通知。编译运行上面的这段程序,可以看到如下的输出:
DemoTask runtask.
Task finished.
Demo run end.
这里要注意,在收到Notification,处理了事件之后,要主动地release传进来的Notification,否则会发生内存泄漏。后面我们会通过对代码的分析来更详细的了解这样做的原因。
TaskManager的实现
来看TaskManager的实现,同时也再次全面的看一下TaskManager提供的功能即接口。TaskManager这个class的定义如下:
namespace Poco {
class Notification;
class ThreadPool;
class Exception;
class Foundation_API TaskManager
/// The TaskManager manages a collection of tasks
/// and monitors their lifetime.
///
/// A TaskManager has a built-in NotificationCenter that
/// is used to send out notifications on task progress
/// and task states. See the TaskNotification class and its
/// subclasses for the various events that result in a notification.
/// To keep the number of notifications small, a TaskProgressNotification
/// will only be sent out once in 100 milliseconds.
{
public:
typedef AutoPtr<Task> TaskPtr;
typedef std::list<TaskPtr> TaskList;
TaskManager();
/// Creates the TaskManager, using the
/// default ThreadPool.
TaskManager(ThreadPool& pool);
/// Creates the TaskManager, using the
/// given ThreadPool.
~TaskManager();
/// Destroys the TaskManager.
void start(Task* pTask);
/// Starts the given task in a thread obtained
/// from the thread pool.
///
/// The TaskManager takes ownership of the Task object
/// and deletes it when it it finished.
void cancelAll();
/// Requests cancellation of all tasks.
void joinAll();
/// Waits for the completion of all the threads
/// in the TaskManager's thread pool.
///
/// Note: joinAll() will wait for ALL tasks in the
/// TaskManager's ThreadPool to complete. If the
/// ThreadPool has threads created by other
/// facilities, these threads must also complete
/// before joinAll() can return.
TaskList taskList() const;
/// Returns a copy of the internal task list.
int count() const;
/// Returns the number of tasks in the internal task list.
void addObserver(const AbstractObserver& observer);
/// Registers an observer with the NotificationCenter.
/// Usage:
/// Observer<MyClass, MyNotification> obs(*this, &MyClass::handleNotification);
/// notificationCenter.addObserver(obs);
void removeObserver(const AbstractObserver& observer);
/// Unregisters an observer with the NotificationCenter.
static const int MIN_PROGRESS_NOTIFICATION_INTERVAL;
protected:
void postNotification(const Notification::Ptr& pNf);
/// Posts a notification to the task manager's
/// notification center.
void taskStarted(Task* pTask);
void taskProgress(Task* pTask, float progress);
void taskCancelled(Task* pTask);
void taskFinished(Task* pTask);
void taskFailed(Task* pTask, const Exception& exc);
private:
ThreadPool& _threadPool;
TaskList _taskList;
Timestamp _lastProgressNotification;
NotificationCenter _nc;
mutable FastMutex _mutex;
friend class Task;
};
//
// inlines
//
inline int TaskManager::count() const {
FastMutex::ScopedLock lock(_mutex);
return (int) _taskList.size();
}
} // namespace Poco
1. TaskManager有两个构造函数,一个需要传入一个ThreadPool对象的引用作为参数,用于定制通过该TaskManager管理的Task将要运行于其中的线程池;另一个不需要传入任何参数,则通过该TaskManager管理的Task将运行于default ThreadPool中。
2. 如我们前面看到的那样,TaskManager的start(Task* pTask)函数用于启动一个Task的执行。
3. cancelAll()函数用于取消所有Task的执行,joinAll()则用于等待TaskManager的ThreadPool的所有线程执行完成。
4. taskList()和count()是两个getter函数,它们分别用于获取TaskManager内部task的列表,和内部task的个数。
5. addObserver(const AbstractObserver& observer)和removeObserver(const AbstractObserver& observer)分别用于添加和移除观察者。如前所见,我们可以用Observer来监听Task状态的改变。
6. postNotification(const Notification::Ptr& pNf)用于向TaskManager的NotificationCenter post一个notification。后面我们会看到,这个函数主要由Task的postNotification(Notification* pNf)函数调用。我们自己写的Task可以通过后者post notification,这样就可以定制我们自己的Task的notification类型及时机,以方便我们对与Task的状态行为等有着更多的控制。
7. taskStarted(Task* pTask)、taskProgress(Task* pTask, float progress)、taskCancelled(Task* pTask)、taskFinished(Task* pTask)和taskFailed(Task* pTask, const Exception& exc)这几个函数,主要是在TaskManager内部,用来针对Task状态的改变进行通知。
接着来看TaskManager的实现:
namespace Poco {
const int TaskManager::MIN_PROGRESS_NOTIFICATION_INTERVAL = 100000; // 100 milliseconds
TaskManager::TaskManager()
: _threadPool(ThreadPool::defaultPool()) {
}
TaskManager::TaskManager(ThreadPool& pool)
: _threadPool(pool) {
}
TaskManager::~TaskManager() {
}
void TaskManager::start(Task* pTask) {
TaskPtr pAutoTask(pTask); // take ownership immediately
FastMutex::ScopedLock lock(_mutex);
pAutoTask->setOwner(this);
pAutoTask->setState(Task::TASK_STARTING);
_taskList.push_back(pAutoTask);
try {
_threadPool.start(*pAutoTask, pAutoTask->name());
} catch (...) {
// Make sure that we don't act like we own the task since
// we never started it. If we leave the task on our task
// list, the size of the list is incorrect.
_taskList.pop_back();
throw;
}
}
void TaskManager::cancelAll() {
FastMutex::ScopedLock lock(_mutex);
for (TaskList::iterator it = _taskList.begin(); it != _taskList.end(); ++it) {
(*it)->cancel();
}
}
void TaskManager::joinAll() {
_threadPool.joinAll();
}
TaskManager::TaskList TaskManager::taskList() const {
FastMutex::ScopedLock lock(_mutex);
return _taskList;
}
void TaskManager::addObserver(const AbstractObserver& observer) {
_nc.addObserver(observer);
}
void TaskManager::removeObserver(const AbstractObserver& observer) {
_nc.removeObserver(observer);
}
void TaskManager::postNotification(const Notification::Ptr& pNf) {
_nc.postNotification(pNf);
}
void TaskManager::taskStarted(Task* pTask) {
_nc.postNotification(new TaskStartedNotification(pTask));
}
void TaskManager::taskProgress(Task* pTask, float progress) {
FastMutex::ScopedLock lock(_mutex);
if (_lastProgressNotification.isElapsed(MIN_PROGRESS_NOTIFICATION_INTERVAL)) {
_lastProgressNotification.update();
_nc.postNotification(new TaskProgressNotification(pTask, progress));
}
}
void TaskManager::taskCancelled(Task* pTask) {
_nc.postNotification(new TaskCancelledNotification(pTask));
}
void TaskManager::taskFinished(Task* pTask) {
_nc.postNotification(new TaskFinishedNotification(pTask));
FastMutex::ScopedLock lock(_mutex);
for (TaskList::iterator it = _taskList.begin(); it != _taskList.end(); ++it) {
if (*it == pTask) {
_taskList.erase(it);
break;
}
}
}
void TaskManager::taskFailed(Task* pTask, const Exception& exc) {
_nc.postNotification(new TaskFailedNotification(pTask, exc));
}
} // namespace Poco
两个构造函数没有什么值得特别说明的地方,来看start()函数的行为。在start()函数中主要做了这样的一些事情:
1. 立即获取task的所有权,即为Task在函数栈上创建一个智能指针,这样就可以保证后面不管发生了什么,都不会发生不预期的Task对象内存不预期泄漏。
2. 获取mutex,设置task的owner为this,设置task的状态为Task::TASK_STARTING,然后将task push进TaskManager的taskList中。
3. 委托_threadPool启动task的执行。可以看到在通过threadPool启动task,抛出了异常时,会将刚刚push进taskList的task给pop出来,以避免发生Task的内存泄漏,并将捕获到的异常再次抛出。
addObserver()、removeObserver()和postNotification()都是简单的将动作委托给notification center。
taskStarted()、taskProgress()、taskCancelled()、taskFinished()和taskFailed()这几个函数基本上主要都是new一个Notification,然后通过notification center post出去。这几个函数都没有通过TaskManager类的postNotification()函数来post notification。
在taskProgress()中,可以看到,这里会对发出TaskProgressNotification的频率做一些控制,以免不当的Task发出过多的Progress通知,消耗过多的资源。
在taskFinished()中,可以看到,在发出通知之外,还会将task从TaskManager的taskList中移除出去。如果应用的代码里没有额外引用task的地方的话,这里将是一个task生命周期的终点。这个函数之后,task会被delete掉,它的所有的资源也会得到释放。
最后再来看TaskManager的析够函数,可以看到在这个函数里是什么动作都没有。在start()函数中我们有看到,会将task的owner设置为this,而在这里却没有reset task的owner为null。这种做法所带来额问题就是,如果threadPool和task的生命周期比TaskManager长的话,在task中就有可能去访问一个已经被释放了的,不存在的TaskManager对象,访问野指针的后果自是不言自明。那threadPool和task的生命周期到底有没有可能比TaskManager长呢?threadPool和task都是从TaskManager的外部获取的,相信这种可能性还是很大的。
这里都没有看到通知动作的触发,也就是对于taskStarted()、taskProgress()、taskCancelled()、taskFinished()和taskFailed()这几个函数的调用呢。其实通知都是在Task中进行的。接着我们就来看Task的实现。
Task的实现
先来看Task类的定义:
namespace Poco {
class TaskManager;
class Notification;
class NotificationCenter;
class Foundation_API Task: public Runnable, public RefCountedObject
/// A Task is a subclass of Runnable that has a name
/// and supports progress reporting and cancellation.
///
/// A TaskManager object can be used to take care of the
/// lifecycle of a Task.
{
public:
enum TaskState
{
TASK_IDLE,
TASK_STARTING,
TASK_RUNNING,
TASK_CANCELLING,
TASK_FINISHED
};
Task(const std::string& name);
/// Creates the Task.
const std::string& name() const;
/// Returns the task's name.
float progress() const;
/// Returns the task's progress.
/// The value will be between 0.0 (just started)
/// and 1.0 (completed).
virtual void cancel();
/// Requests the task to cancel itself. For cancellation
/// to work, the task's runTask() method must periodically
/// call isCancelled() and react accordingly.
///
/// Can be overridden to implement custom behavior,
/// but the base class implementation of cancel() should
/// be called to ensure proper behavior.
bool isCancelled() const;
/// Returns true if cancellation of the task has been
/// requested.
///
/// A Task's runTask() method should periodically
/// call this method and stop whatever it is doing in an
/// orderly way when this method returns true.
TaskState state() const;
/// Returns the task's current state.
void reset();
/// Sets the task's progress to zero and clears the
/// cancel flag.
virtual void runTask() = 0;
/// Do whatever the task needs to do. Must
/// be overridden by subclasses.
void run();
/// Calls the task's runTask() method and notifies the owner
/// of the task's start and completion.
protected:
bool sleep(long milliseconds);
/// Suspends the current thread for the specified
/// amount of time.
///
/// If the task is cancelled while it is sleeping,
/// sleep() will return immediately and the return
/// value will be true. If the time interval
/// passes without the task being cancelled, the
/// return value is false.
///
/// A Task should use this method in favor of Thread::sleep().
void setProgress(float progress);
/// Sets the task's progress.
/// The value should be between 0.0 (just started)
/// and 1.0 (completed).
virtual void postNotification(Notification* pNf);
/// Posts a notification to the task manager's
/// notification center.
///
/// A task can use this method to post custom
/// notifications about its progress.
void setOwner(TaskManager* pOwner);
/// Sets the (optional) owner of the task.
TaskManager* getOwner() const;
/// Returns the owner of the task, which may be NULL.
void setState(TaskState state);
/// Sets the task's state.
virtual ~Task();
/// Destroys the Task.
private:
Task();
Task(const Task&);
Task& operator = (const Task&);
std::string _name;
TaskManager* _pOwner;
float _progress;
TaskState _state;
Event _cancelEvent;
mutable FastMutex _mutex;
friend class TaskManager;
};
//
// inlines
//
inline const std::string& Task::name() const {
return _name;
}
inline float Task::progress() const {
FastMutex::ScopedLock lock(_mutex);
return _progress;
}
inline bool Task::isCancelled() const {
return _state == TASK_CANCELLING;
}
inline Task::TaskState Task::state() const {
return _state;
}
inline TaskManager* Task::getOwner() const {
FastMutex::ScopedLock lock(_mutex);
return _pOwner;
}
} // namespace Poco
Task继承自Runnable和RefCountedObject。继承Runnable是为了能放到ThreadPool上执行,而继承RefCountedObject,则是为了能用智能指针AutoPtr管理堆上分配的Task对象。
然后来看Task类的实现:
namespace Poco {
Task::Task(const std::string& name)
: _name(name),
_pOwner(0),
_progress(0),
_state(TASK_IDLE),
_cancelEvent(false) {
}
Task::~Task() {
}
void Task::cancel() {
_state = TASK_CANCELLING;
_cancelEvent.set();
if (_pOwner)
_pOwner->taskCancelled(this);
}
void Task::reset() {
_progress = 0.0;
_state = TASK_IDLE;
_cancelEvent.reset();
}
void Task::run() {
TaskManager* pOwner = getOwner();
if (pOwner)
pOwner->taskStarted(this);
try {
_state = TASK_RUNNING;
runTask();
} catch (Exception& exc) {
if (pOwner)
pOwner->taskFailed(this, exc);
} catch (std::exception& exc) {
if (pOwner)
pOwner->taskFailed(this, SystemException(exc.what()));
} catch (...) {
if (pOwner)
pOwner->taskFailed(this, SystemException("unknown exception"));
}
_state = TASK_FINISHED;
if (pOwner)
pOwner->taskFinished(this);
}
bool Task::sleep(long milliseconds) {
return _cancelEvent.tryWait(milliseconds);
}
void Task::setProgress(float progress) {
FastMutex::ScopedLock lock(_mutex);
_progress = progress;
if (_pOwner)
_pOwner->taskProgress(this, _progress);
}
void Task::setOwner(TaskManager* pOwner) {
FastMutex::ScopedLock lock(_mutex);
_pOwner = pOwner;
}
void Task::setState(TaskState state) {
_state = state;
}
void Task::postNotification(Notification* pNf) {
poco_check_ptr(pNf);
FastMutex::ScopedLock lock(_mutex);
if (_pOwner) {
_pOwner->postNotification(pNf);
}
}
} // namespace Poco
TaskManager中通过threadPool的start()函数来启动一个task的执行。threadPool的start()的参数是一个Runnable,在threadPool的thread中会去执行这个Runnable的run()函数。
TaskManager的Task最为特别的地方也正在与它的run()函数的实现了,正是在这个函数里实现了对我们的任务生命周期管理的主要部分。可以看到在run()函数中:
1. 首先获取task的owner,也就是管理这个task的TaskManager。
2. 如果owner存在,则执行owner的taskStarted()发出通知,表示一个task要启动执行了。
3. 将task的状态更新为TASK_RUNNING,然后执行runTask()函数。runTask()函数中主要放我们自己的任务的逻辑。如果在runTask()函数中发生了异常,而owner又是存在的,则会调用owner的taskFailed()函数,以通知应用程序,task的执行发生了错误。
可以看到这里会捕获所有的异常。这样做也是为了防止由于应用程序的代码写的不好,而把Poco的TaskManager/ThreadPool/Task这个异步执行的框架给搞挂了。
4. 更新状态为TASK_FINISHED。如果owner存在,则执行owner的taskFinished()发出通知,表示一个task的执行结束了。如我们前面看到的,在TaskManager的taskFinished()中,会将task移出taskList,从而让Task可以被release调用。
然后来看Task的setProgress()。我们实现的任务可以借助这个函数通过TaskManager的notification center将任务的执行进度通知出去。这个函数和android的AsyncTask的publishProgress()及onProgressUpdate()还是颇有几分神似。只是在这里回调同样在线程池的线程里执行。
接着来看cancel()和isCancelled()函数。应用程序可以通过cancel()来干预一个task的生命周期及执行,即取消task的执行。在cancel()函数中主要就是更新了task的state,唤醒了等待在_cancelEvent上的task,并发出一个通知。如同所有其它的异步任务执行框架那样,如java的Executor,android的AsyncTask等,这里的*cancel()函数同样不能强制地终止一个task的执行,它也只是设置一个标记。要想对task的生命周期有一个更完善的管理,同样需要我们在实现*runTask()时,能够记得在适当的时候调用isCancelled()检查task是否已经被cancel掉,主动地清理资源并退出执行**。
另外值得注意的是sleep()函数,它会等在_cancelEvent****上休眠,如我们前面分析的,cancel()函数会唤醒这种休眠。因而如果在实现的任务中,有需要休眠的地方,最后使用Task的这个sleep()函数,这样显然更加方便任务的生命周期管理。
向TaskManager注册的observer,会接收到TaskManager所有task的某一类型的通知。对于某些消息类型,这种做法有可能会带来一些额外不必要的低效。
Poco库的Notification
来看一下Poco库的Notification框架。如我们前面看到的,这个框架包括了NotificationCenter,Notification,AbstractObserver及Observer等class。我们创建一个NotificationCenter的对象,然后可以向这个对象注册/移除AbstractObserver,同时可以通过这个对象post notification出去,post了notification之后,之前注册的AbstractObserver的callback会被调到。
可见Poco库的Notification与android的Notification是大为不同的,这是一个比较典型的观察者模式的实现,这套东西倒是和java的Observable/Observer比较相似。可以将NotificationCenter理解为一个AbstractObserver的容器,比如list,或vector等。而post notification则是遍历这个容器中的所有元素,并执行每个元素的特定方法。
NotificationCenter是这一套东西的核心,因而就先来看这个类的定义及实现:
namespace Poco {
class AbstractObserver;
class Foundation_API NotificationCenter
{
public:
NotificationCenter();
/// Creates the NotificationCenter.
~NotificationCenter();
/// Destroys the NotificationCenter.
void addObserver(const AbstractObserver& observer);
/// Registers an observer with the NotificationCenter.
/// Usage:
/// Observer<MyClass, MyNotification> obs(*this, &MyClass::handleNotification);
/// notificationCenter.addObserver(obs);
///
/// Alternatively, the NObserver template class can be used instead of Observer.
void removeObserver(const AbstractObserver& observer);
/// Unregisters an observer with the NotificationCenter.
bool hasObserver(const AbstractObserver& observer) const;
/// Returns true if the observer is registered with this NotificationCenter.
void postNotification(Notification::Ptr pNotification);
/// Posts a notification to the NotificationCenter.
/// The NotificationCenter then delivers the notification
/// to all interested observers.
/// If an observer throws an exception, dispatching terminates
/// and the exception is rethrown to the caller.
/// Ownership of the notification object is claimed and the
/// notification is released before returning. Therefore,
/// a call like
/// notificationCenter.postNotification(new MyNotification);
/// does not result in a memory leak.
bool hasObservers() const;
/// Returns true iff there is at least one registered observer.
///
/// Can be used to improve performance if an expensive notification
/// shall only be created and posted if there are any observers.
std::size_t countObservers() const;
/// Returns the number of registered observers.
static NotificationCenter& defaultCenter();
/// Returns a reference to the default
/// NotificationCenter.
private:
typedef SharedPtr<AbstractObserver> AbstractObserverPtr;
typedef std::vector<AbstractObserverPtr> ObserverList;
ObserverList _observers;
mutable Mutex _mutex;
};
} // namespace Poco
然后是实现:
namespace Poco {
NotificationCenter::NotificationCenter() {
}
NotificationCenter::~NotificationCenter() {
}
void NotificationCenter::addObserver(const AbstractObserver& observer) {
Mutex::ScopedLock lock(_mutex);
_observers.push_back(observer.clone());
}
void NotificationCenter::removeObserver(const AbstractObserver& observer) {
Mutex::ScopedLock lock(_mutex);
for (ObserverList::iterator it = _observers.begin(); it != _observers.end(); ++it) {
if (observer.equals(**it)) {
(*it)->disable();
_observers.erase(it);
return;
}
}
}
bool NotificationCenter::hasObserver(const AbstractObserver& observer) const {
Mutex::ScopedLock lock(_mutex);
for (ObserverList::const_iterator it = _observers.begin(); it != _observers.end(); ++it)
if (observer.equals(**it))
return true;
return false;
}
void NotificationCenter::postNotification(Notification::Ptr pNotification) {
poco_check_ptr(pNotification);
ScopedLockWithUnlock<Mutex> lock(_mutex);
ObserverList observersToNotify(_observers);
lock.unlock();
for (ObserverList::iterator it = observersToNotify.begin(); it != observersToNotify.end(); ++it) {
(*it)->notify(pNotification);
}
}
bool NotificationCenter::hasObservers() const {
Mutex::ScopedLock lock(_mutex);
return !_observers.empty();
}
std::size_t NotificationCenter::countObservers() const {
Mutex::ScopedLock lock(_mutex);
return _observers.size();
}
namespace {
static SingletonHolder<NotificationCenter> sh;
}
NotificationCenter& NotificationCenter::defaultCenter() {
return *sh.get();
}
} // namespace Poco
可以看到,基本上也就是一些比较标准的容器操作。 NotificationCenter 使用STL的vector来保存 AbstractObserver ,因而,这个类也主要是对vector的操作的封装。
Poco的NotificationCenter还会创建一个default的实例。
在postNotification()函数的实现中可以看到,发送通知,主要是调用AbstractObserver的notify()回调。
接着在来看一下Notification的定义和实现,显示class的定义:
class Foundation_API Notification: public RefCountedObject
/// The base class for all notification classes used
/// with the NotificationCenter and the NotificationQueue
/// classes.
/// The Notification class can be used with the AutoPtr
/// template class.
{
public:
typedef AutoPtr<Notification> Ptr;
Notification();
/// Creates the notification.
virtual std::string name() const;
/// Returns the name of the notification.
/// The default implementation returns the class name.
protected:
virtual ~Notification();
};
} // namespace Poco
然后是Notification类的实现:
namespace Poco {
Notification::Notification() {
}
Notification::~Notification() {
}
std::string Notification::name() const {
return typeid(*this).name();
}
} // namespace Poco
这个class倒是没有特别值得说明的地方。实际用到的Notification对象的意义,主要是它的子类赋予的。
然后是AbstractObserver,定义如下:
class Foundation_API AbstractObserver
/// The base class for all instantiations of
/// the Observer and NObserver template classes.
{
public:
AbstractObserver();
AbstractObserver(const AbstractObserver& observer);
virtual ~AbstractObserver();
AbstractObserver& operator = (const AbstractObserver& observer);
virtual void notify(Notification* pNf) const = 0;
virtual bool equals(const AbstractObserver& observer) const = 0;
virtual bool accepts(Notification* pNf) const = 0;
virtual AbstractObserver* clone() const = 0;
virtual void disable() = 0;
};
实现如下:
namespace Poco {
AbstractObserver::AbstractObserver() {
}
AbstractObserver::AbstractObserver(const AbstractObserver& observer) {
}
AbstractObserver::~AbstractObserver() {
}
AbstractObserver& AbstractObserver::operator =(const AbstractObserver& observer) {
return *this;
}
} // namespace Poco
对于AbstractObserver这个class,也不再赘述。
接着在来看一个Poco库中,方便这套机制使用的class,也就是Observer类:
template<class C, class N>
class Observer : public AbstractObserver
/// This template class implements an adapter that sits between
/// a NotificationCenter and an object receiving notifications
/// from it. It is quite similar in concept to the
/// RunnableAdapter, but provides some NotificationCenter
/// specific additional methods.
/// See the NotificationCenter class for information on how
/// to use this template class.
///
/// Instead of the Observer class template, you might want to
/// use the NObserver class template, which uses an AutoPtr to
/// pass the Notification to the callback function, thus freeing
/// you from memory management issues.
{
public:
typedef void (C::*Callback)(N*);
Observer(C& object, Callback method)
: _pObject(&object),
_method(method) {
}
Observer(const Observer& observer)
: AbstractObserver(observer),
_pObject(observer._pObject),
_method(observer._method) {
}
~Observer() {
}
Observer& operator =(const Observer& observer) {
if (&observer != this) {
_pObject = observer._pObject;
_method = observer._method;
}
return *this;
}
void notify(Notification* pNf) const {
Poco::Mutex::ScopedLock lock(_mutex);
if (_pObject) {
N* pCastNf = dynamic_cast<N*>(pNf);
if (pCastNf) {
pCastNf->duplicate();
(_pObject->*_method)(pCastNf);
}
}
}
bool equals(const AbstractObserver& abstractObserver) const {
const Observer* pObs = dynamic_cast<const Observer*>(&abstractObserver);
return pObs && pObs->_pObject == _pObject && pObs->_method == _method;
}
bool accepts(Notification* pNf) const {
return dynamic_cast<N*>(pNf) != 0;
}
AbstractObserver* clone() const {
return new Observer(*this);
}
void disable() {
Poco::Mutex::ScopedLock lock(_mutex);
_pObject = 0;
}
private:
Observer();
C* _pObject;
Callback _method;
mutable Poco::Mutex _mutex;
};
} // namespace Poco
Observer是一个模板类。特别值得关注的是notify()函数。C++的dynamic_cast在一个对象不能转为目标类型时,会返回NULL,这个地方会在dynamic_cast返回NULL时,不将实际的通知发送出去,从而就实现了一个非常好的功能,也就是我们可以针对特定类型的Notification来注册Observer。或者说,尽管通过Observer类实现的观察者也会在NotificationCenter发出任何notification时被通知,但只有我们想要监听的特定类型的Notification事件才会实际被传递到我们app的code。
Done。