Poco::TimedNotificationQueue

Poco::TimedNotificationQueue を紹介します。

子スレッドから時刻指定の Notification を enqueue し、メインスレッドで dequeue するサンプルです。

TimedNotificationQueueTest.cpp

・3つの Child スレッドから、それぞれ現在時刻+α(最大 500msec)の時刻指定で Notification を
 3つずつ enqueue する。
・enqueue する時に、指定時刻を表示。
・時刻は UTC を渡す(つまり、Loacl 時刻ではない)ことに注意。
Poco::TimedNotificationQueue の場合、dequeue するのは1つだけ(つまり複数スレッドで dequeue
 してはいけない)という制約があるので、ここでは Main スレッドで dequeue。
 (前回の Worker Thread パターンとは主従が逆)
・dequeue する時に、指定時刻を表示。

#include <Poco/Format.h>
#include <Poco/Notification.h>
#include <Poco/TimedNotificationQueue.h>
#include <Poco/AtomicCounter.h>
#include <Poco/DateTime.h>
#include <Poco/Timespan.h>
#include <Poco/ThreadPool.h>
#include <Poco/Thread.h>
#include <Poco/Runnable.h>
#include <Poco/AutoPtr.h>
#include <Poco/Random.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Timezone.h>
 
#include <string>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
 
const int kNumEnqueueByChild = 3;
const long kSleepTime = 200;
const long kScheduleMaxTime = 500;
 
class ChildNotification : public Poco::Notification
{
public:
	ChildNotification(int data, const std::string& name, const Poco::DateTime& datetime):
		m_data(data)
	,	m_name(name)
	,	m_datetime(datetime)
	{
		m_datetime.makeLocal(Poco::Timezone::tzd());
	}
 
	int data() const
	{
		return m_data;
	}
 
	std::string name() const
	{
		return m_name;
	}
 
	std::string datetime() const
	{
		return Poco::DateTimeFormatter::format(m_datetime.timestamp(), "%H:%M:%S.%i");
	}
 
private:
	int			m_data;
	const std::string	m_name;
	Poco::DateTime		m_datetime;
};
 
class Child : public Poco::Runnable
{
public:
	typedef Poco::AutoPtr<ChildNotification> ChildNotificationPtr;
 
	Child(const std::string& name, Poco::TimedNotificationQueue& queue, ScopedLogMessage& msg):
		m_name(name)
	,	m_queue(queue)
	,	m_msg(msg)
	{
		m_msg.Message(Poco::format("  %s created", m_name));
	}
 
	~Child()
	{
		m_msg.Message(Poco::format("  %s deleted", m_name));
	}
 
	void run()
	{
		for(int i=0; i<kNumEnqueueByChild; ++i)
		{
			int counter = ++m_counter;
			Poco::DateTime datetime;
			datetime += Poco::Timespan(m_rnd.next(kScheduleMaxTime)*1000);
			m_queue.enqueueNotification(new ChildNotification(counter, m_name, datetime), datetime.timestamp());
			datetime.makeLocal(Poco::Timezone::tzd());
			m_msg.Message(Poco::format("   enqueueNotification #%d from %s (%s)"
							, counter
							, m_name
							, Poco::DateTimeFormatter::format(datetime.timestamp(), "%H:%M:%S.%i")));
		}
	}
 
	static int NumEnqueued(void)
	{
		return m_counter;
	}
 
private:
	std::string			m_name;
	Poco::TimedNotificationQueue&	m_queue;
	ScopedLogMessage&		m_msg;
	static Poco::AtomicCounter	m_counter;
	static Poco::Random		m_rnd;
};
 
Poco::AtomicCounter Child::m_counter(0);
Poco::Random Child::m_rnd;
 
int main(int /*argc*/, char** /*argv*/)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("TimedNotificationQueueTest ", "start", "end");
 
	Poco::TimedNotificationQueue queue;
 
	Child child1("Child 1", queue, msg);
	Child child2("Child 2", queue, msg);
	Child child3("Child 3", queue, msg);
 
	Poco::ThreadPool::defaultPool().start(child1);
	Poco::ThreadPool::defaultPool().start(child2);
	Poco::ThreadPool::defaultPool().start(child3);
 
	int numDequeued = 0;
	while(numDequeued < Child::NumEnqueued())
	{
		Poco::Notification::Ptr pNf(queue.waitDequeueNotification());
		if(pNf)
		{
			Child::ChildNotificationPtr pChildNf = pNf.cast<ChildNotification>();
			if(pChildNf)
			{
				msg.Message(Poco::format("    got child notification #%d from %s (%s)"
								, pChildNf->data()
								, pChildNf->name()
								, pChildNf->datetime()));
				++numDequeued;
				Poco::Thread::sleep(kSleepTime);
			}
		}
		else break;
	}
 
	return 0;
}

Results of execution

Poco::TimedNotificationQueue の場合は、queue に積んだ順ではなく、指定した Timestamp の
 若い順に処理される。

[0] TimedNotificationQueueTest start
[0]   Child 1 created
[0]   Child 2 created
[0]   Child 3 created
[1]    enqueueNotification #1 from Child 1 (05:17:15.460)
[2]    enqueueNotification #2 from Child 2 (05:17:15.528)
[3]    enqueueNotification #3 from Child 3 (05:17:15.449)
[1]    enqueueNotification #4 from Child 1 (05:17:15.573)
[2]    enqueueNotification #5 from Child 2 (05:17:15.374)
[3]    enqueueNotification #6 from Child 3 (05:17:15.162)
[1]    enqueueNotification #7 from Child 1 (05:17:15.277)
[2]    enqueueNotification #8 from Child 2 (05:17:15.212)
[3]    enqueueNotification #9 from Child 3 (05:17:15.555)
[0]     got child notification #6 from Child 3 (05:17:15.162)
[0]     got child notification #8 from Child 2 (05:17:15.212)
[0]     got child notification #7 from Child 1 (05:17:15.277)
[0]     got child notification #5 from Child 2 (05:17:15.374)
[0]     got child notification #3 from Child 3 (05:17:15.449)
[0]     got child notification #1 from Child 1 (05:17:15.460)
[0]     got child notification #2 from Child 2 (05:17:15.528)
[0]     got child notification #9 from Child 3 (05:17:15.555)
[0]     got child notification #4 from Child 1 (05:17:15.573)
[0]   Child 3 deleted
[0]   Child 2 deleted
[0]   Child 1 deleted
[0] TimedNotificationQueueTest end

Downloads

ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年6月10日からのダウンロード数:848

Subversion

・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。

Powered by POCO Copyright © 2010 Round Square Inc. All rights reserved.


Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>