Poco::NotificationQueue と Poco::PriorityNotificationQueue を紹介します。
メインスレッドで Poco::NotificationQueue や Poco::PriorityNotificationQueue に enqueue して、3つのワーカースレッドで順次 dequeue するというサンプルです。
デザインパターンで言うと Worker Thread パターンになります。
NotificationQueueTest.cpp
・Foundation/samples/NotificationQueue とほとんど同じ処理だが、Poco::NotificationQueue と
Poco::PriorityNotificationQueue の両者を処理できるように Worker を template 化。
・Poco::NotificationQueue と Poco::PriorityNotificationQueue との enqueueNotification() の引数の数の
違いを template の特殊化で対応。ついでに、非対応クラスを渡されてインスタンス化され、
MyEnqueueNotification() が呼ばれたら、非対応な旨表示。
#include <Poco/Format.h> #include <Poco/Notification.h> #include <Poco/NotificationQueue.h> #include <Poco/PriorityNotificationQueue.h> #include <Poco/ThreadPool.h> #include <Poco/Thread.h> #include <Poco/Runnable.h> #include <Poco/Random.h> #include <Poco/AutoPtr.h> #include <string> #include <typeinfo> #include "ScopedLogMessage.h" #include "PrepareConsoleLogger.h" const int kNumQueue = 12; const long kSleepMaxTime = 200; const long kSleepWaitTime = 500; class WorkNotification : public Poco::Notification { public: WorkNotification(int data): m_data(data) { } int data() const { return m_data; } private: int m_data; }; template<class T> class Worker : public Poco::Runnable { typedef Poco::AutoPtr<WorkNotification> WorkNotificationPtr; public: Worker(const std::string& name, T& queue, ScopedLogMessage& msg): m_name(name) , m_queue(queue) , m_msg(msg) { m_msg.Message(Poco::format(" %s created", m_name)); } ~Worker() { m_msg.Message(Poco::format(" %s deleted", m_name)); } void run() { Poco::Random rnd; for(;;) { Poco::Notification::Ptr pNf(m_queue.waitDequeueNotification()); if(pNf) { WorkNotificationPtr pWorkNf = pNf.cast<WorkNotification>(); if(pWorkNf) { m_msg.Message(Poco::format(" %s got work notification %d", m_name, pWorkNf->data())); Poco::Thread::sleep(rnd.next(kSleepMaxTime)); } } else break; } } private: std::string m_name; T& m_queue; ScopedLogMessage& m_msg; }; template<class T> class MyNotificationQueue : public T { public: MyNotificationQueue(ScopedLogMessage& msg) : m_msg(msg) , m_numEnqueued(0) { } void MyEnqueueNotification(Poco::Notification::Ptr pNotification) { m_msg.Message(Poco::format("Class %s is not supported!", std::string(typeid(T).name()))); } private: ScopedLogMessage& m_msg; int m_numEnqueued; }; template<> void MyNotificationQueue<Poco::NotificationQueue>::MyEnqueueNotification(Poco::Notification::Ptr pNotification) { enqueueNotification(pNotification); ++m_numEnqueued; } template<> void MyNotificationQueue<Poco::PriorityNotificationQueue>::MyEnqueueNotification(Poco::Notification::Ptr pNotification) { enqueueNotification(pNotification, kNumQueue-m_numEnqueued); ++m_numEnqueued; } template<class T> void TestNotificationQueue(ScopedLogMessage& msg, const std::string& title) { msg.Message(Poco::format("--- %s ---", title)); MyNotificationQueue<T> queue(msg); Worker< MyNotificationQueue<T> > worker1("Worker 1", queue, msg); Worker< MyNotificationQueue<T> > worker2("Worker 2", queue, msg); Worker< MyNotificationQueue<T> > worker3("Worker 3", queue, msg); for(int i=0; i<kNumQueue; ++i) { queue.MyEnqueueNotification(new WorkNotification(i)); } Poco::ThreadPool::defaultPool().start(worker1); Poco::ThreadPool::defaultPool().start(worker2); Poco::ThreadPool::defaultPool().start(worker3); while(!queue.empty()) { Poco::Thread::sleep(kSleepMaxTime); } Poco::Thread::sleep(kSleepWaitTime); queue.wakeUpAll(); Poco::ThreadPool::defaultPool().joinAll(); } int main(int /*argc*/, char** /*argv*/) { PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION); ScopedLogMessage msg("NotificationQueueTest ", "start", "end"); TestNotificationQueue<Poco::NotificationQueue>(msg, "Poco::NotificationQueue"); TestNotificationQueue<Poco::PriorityNotificationQueue>(msg, "Poco::PriorityNotificationQueue"); return 0; } |
Results of execution
・Poco::NotificationQueue の場合は、queue に積んだ順に処理される。
・Poco::PriorityNotificationQueue の場合は、queue に積んだ順ではなく、priority 値の小さい順に
処理される。
・どの Worker(どの thread)で処理されるかは、実行する度に変化。
[0] NotificationQueueTest start [0] --- Poco::NotificationQueue --- [0] Worker 1 created [0] Worker 2 created [0] Worker 3 created [2] Worker 2 got work notification 0 [1] Worker 1 got work notification 1 [3] Worker 3 got work notification 2 [2] Worker 2 got work notification 3 [1] Worker 1 got work notification 4 [3] Worker 3 got work notification 5 [2] Worker 2 got work notification 6 [1] Worker 1 got work notification 7 [3] Worker 3 got work notification 8 [2] Worker 2 got work notification 9 [1] Worker 1 got work notification 10 [3] Worker 3 got work notification 11 [0] Worker 3 deleted [0] Worker 2 deleted [0] Worker 1 deleted [0] --- Poco::PriorityNotificationQueue --- [0] Worker 1 created [0] Worker 2 created [0] Worker 3 created [3] Worker 3 got work notification 11 [1] Worker 1 got work notification 10 [2] Worker 2 got work notification 9 [3] Worker 3 got work notification 8 [1] Worker 1 got work notification 7 [2] Worker 2 got work notification 6 [3] Worker 3 got work notification 5 [1] Worker 1 got work notification 4 [2] Worker 2 got work notification 3 [3] Worker 3 got work notification 2 [1] Worker 1 got work notification 1 [2] Worker 2 got work notification 0 [0] Worker 3 deleted [0] Worker 2 deleted [0] Worker 1 deleted [0] NotificationQueueTest end |
Downloads
・ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年6月8日からのダウンロード数:1136
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
Reference
・POCO::Foundationでデザインパターン – マルチスレッド編 –
・http://pocoproject.org にある NotificationsEvents のプレセンテーション。(PDF)
![]() |
Copyright © 2010 Round Square Inc. All rights reserved. |
---|
0 Comments.