Poco是一个强大的,用于构建C++程序的类库,它提供了许多非常好用的部件来帮助我们更快的开发C++应用程序,异步执行的相关部件正是这些好用的部件中的一部分。这里我们来看一下Poco库的异步执行组件的实现。
Poco库的异步执行组件主要有TaskManager,Task,ThreadPool等等。这里就主要从这些组件着手进行分析。
首先来看一下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这个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类的定义:
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框架。如我们前面看到的,这个框架包括了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。