Monthly Archives: July 2010

Poco::RWLock

Poco::RWLock を紹介します。

Poco::RWLock を使うと、複数の同時動作可能な reader もしくは唯一の排他的な writer を実現できます。

RWLockTest.cpp

・スレッドを5つ立て、それぞれで同一のカウンタを複数回 read/write し、カウンタの最終値に矛盾が
 無いことを確認し、処理時間も計測。
Poco::RWLock::readLock()Poco::RWLock::writeLock()Poco::RWLock::unlock() の組み合わせでも
 もちろん動作するが、RAII イディオムを使った
  Poco::ScopedReadRWLock()
  Poco::ScopedWriteRWLock()
 を利用。

#include <Poco/Format.h>
#include <Poco/Runnable.h>
#include <Poco/Thread.h>
#include <Poco/RWLock.h>
#include <Poco/Stopwatch.h>
 
#include <string>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
 
const int kNumLoops = 1000;
const int kNumRunnable = 5;
 
class RWLockRunnable: public Poco::Runnable
{
public:
	RWLockRunnable(Poco::RWLock& lock, volatile int& counter) :
		m_Lock(lock)
	,	m_Counter(counter)
	,	m_Ok(true)
	{
	}
 
	void run()
	{
		int lastCount = 0;
		for(int i=0; i<kNumLoops; ++i)
		{
			{	// scope for read lock
				Poco::ScopedReadRWLock lock(m_Lock);
 
				lastCount = m_Counter;
				for(int k=0; k<100; ++k)
				{
					if(m_Counter != lastCount)
					{
						m_Ok = false;
					}
					Poco::Thread::yield();
				}
			}
 
			{	// scope for write lock
				Poco::ScopedWriteRWLock lock(m_Lock);
 
				for(int k=0; k<100; ++k)
				{
					--m_Counter;
					Poco::Thread::yield();
				}
				for(int k=0; k<100; ++k)
				{
					++m_Counter;
					Poco::Thread::yield();
				}
				++m_Counter;
				if(m_Counter <= lastCount)
				{
					m_Ok = false;
				}
			}
		}
	}
 
	bool ok() const
	{
		return m_Ok;
	}
 
private:
	Poco::RWLock&	m_Lock;
	volatile int&	m_Counter;
	bool		m_Ok;
};
 
int main(int /*argc*/, char** /*argv*/)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("RWLockTest ", "start", "end");
 
	Poco::Stopwatch stopwatch;
	stopwatch.start();
 
	Poco::RWLock lock;
	int counter = 0;
 
	RWLockRunnable* pRunnable[kNumRunnable];
	Poco::Thread thread[kNumRunnable];
 
	for(int i=0; i<kNumRunnable; ++i)
	{
		pRunnable[i] = new RWLockRunnable(lock, counter);
		thread[i].start(*pRunnable[i]);
	}
 
	for(int i=0; i<kNumRunnable; ++i)
	{
		thread[i].join();
		if(!pRunnable[i]->ok())
		{
			msg.Message(Poco::format(" RWLockRunnable[%i] failed!", i));
		}
		delete pRunnable[i];
	}
 
	stopwatch.stop();
 
	msg.Message(Poco::format(" counter = %i (expected: %i)", counter, kNumLoops*kNumRunnable));
	msg.Message(Poco::format(" Elapsed time = %.3fmSec", (1000.0 * stopwatch.elapsed()) / stopwatch.resolution()));
 
	return 0;
}

Results of execution

[0] RWLockTest start
[0]  counter = 5000 (expected: 5000)
[0]  Elapsed time = 1431.262mSec
[0] RWLockTest end

Downloads

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

Subversion

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

Reference

http://pocoproject.org にある Threads のプレセンテーション。(PDF)

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