Poco::Mutex と Poco::FastMutex を紹介します。
両者ともマルチスレッド環境での共有リソースのアクセスの同期に使います。
Poco::Mutex は、同じスレッドから何度もロックしても問題ありませんが、Poco::FastMutex は、既にロックしている時に同じスレッドから再びロックするとデッドロックします。
MutexTest.cpp
・スレッドを5つ立て、それぞれで同一のカウンタを複数回 read/write し、カウンタの最終値に矛盾が
無いことを確認し、処理時間も計測。
・Poco::Mutex と Poco::FastMutex の両者で同じテストを実行。
・Poco::Mutex::lock() と Poco::Mutex::unlock() や Poco::FastMutex::lock() と Poco::FastMutex::unlock()
の組み合わせでももちろん動作するが、RAII イディオムを使った Poco::ScopedLock を利用。
#include <Poco/Format.h> #include <Poco/Runnable.h> #include <Poco/Thread.h> #include <Poco/Mutex.h> #include <Poco/ScopedLock.h> #include <Poco/Stopwatch.h> #include <string> #include "ScopedLogMessage.h" #include "PrepareConsoleLogger.h" const int kNumLoops = 1000; const int kNumRunnable = 5; template <class T> class MutexRunnable: public Poco::Runnable { public: MutexRunnable(T& 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::ScopedLock<T> 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::ScopedLock<T> 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: T& m_Lock; volatile int& m_Counter; bool m_Ok; }; template <class T> void TestMutex(ScopedLogMessage& msg, const std::string& name) { msg.Message(Poco::format(" --- %s ---", name)); Poco::Stopwatch stopwatch; stopwatch.start(); T lock; int counter = 0; MutexRunnable<T>* pRunnable[kNumRunnable]; Poco::Thread thread[kNumRunnable]; for(int i=0; i<kNumRunnable; ++i) { pRunnable[i] = new MutexRunnable<T>(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(" MutexRunnable[%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())); } int main(int /*argc*/, char** /*argv*/) { PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION); ScopedLogMessage msg("MutexTest ", "start", "end"); TestMutex<Poco::Mutex>(msg, "Poco::Mutex test"); TestMutex<Poco::FastMutex>(msg, "Poco::FastMutex test"); return 0; } |
Results of execution
– On Linux
[0] MutexTest start [0] --- Poco::Mutex test --- [0] counter = 5000 (expected: 5000) [0] Elapsed time = 2387.954mSec [0] --- Poco::FastMutex test --- [0] counter = 5000 (expected: 5000) [0] Elapsed time = 2142.277mSec [0] MutexTest end |
– On Macintosh OSX 10.6.4
[0] MutexTest start [0] --- Poco::Mutex test --- [0] counter = 5000 (expected: 5000) [0] Elapsed time = 990.828mSec [0] --- Poco::FastMutex test --- [0] counter = 5000 (expected: 5000) [0] Elapsed time = 989.493mSec [0] MutexTest end |
– On Windows XP sp3
[0] MutexTest start [0] --- Poco::Mutex test --- [0] counter = 5000 (expected: 5000) [0] Elapsed time = 2765.625mSec [0] --- Poco::FastMutex test --- [0] counter = 5000 (expected: 5000) [0] Elapsed time = 1359.375mSec [0] MutexTest end |
Downloads
・ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年7月31日からのダウンロード数:1174
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
Reference
・http://pocoproject.org にある Threads のプレセンテーション。(PDF)
![]() |
Copyright © 2010 Round Square Inc. All rights reserved. |
---|
ScriptLaboを管理している、eastmonkと申します。
blogへのコメント有難うございます。
以前からこちらのサイトを拝見しておりました。
サンプルコードがダウンロードでき、日本語解説なので
とても助かります。