Poco::SharedMemory を紹介します。
このクラスは、名前のとおり Shared Memory(2つ以上のプロセスでのメモリ共有)を提供しています。
Poco::SharedMemory では2通りの実装があります:
・ファイルベースの Shared Memory
・(識別用の)名前ベースの Shared Memory
この両者を紹介しようと思ってサンプルを作っていたら、後者にバグを見つけたので、ここでは前者だけの紹介になります。
(Bug Report は Forum に出しておきましたが、v1.3.7 に反映されるかは微妙かもしれません)
いずれバグが修正されたら、後者のサンプルも追加します。
(2010.07.06 追記:SharedMemory_POSIX.cpp には反映してもらえました)
(2010.12.24 追記:v1.4.0 に反映されたのですが、さらに幾つか問題があって再提起しました。Bug Reportにその解決方法と、問題が解決した場合用に修正したコードの圧縮ファイルが置いてあります。)
(2011.02.14 追記:v1.4.1 で修正されたので更新しました)
(2011.02.15 追記:比較すべきバージョン番号を間違えていたので更新しました)
今回のサンプルは、Shared Memory の Server と Client、さらにそれらを起動するものと、3つのソースがあります。
SharedMemoryServer.cpp
・Shared Memory のサーバー。
・Poco::Util::ServerApplication を使用。
・ServerTask を立ち上げ、その中で周期的に Shared Memory の内容を書き換え。
・最後の行の POCO_SERVER_MAIN は、その中に main() エントリーポイントがあるマクロ。
(Util/include/Poco/Util/ServerApplication.h 参照)
#include <Poco/Util/ServerApplication.h> #include <Poco/Task.h> #include <Poco/TaskManager.h> #include <Poco/SharedMemory.h> #include <Poco/Format.h> #include <Poco/Path.h> #include <Poco/File.h> #include <Poco/FileStream.h> #ifndef POCO_VERSION #include <Poco/Version.h> #endif #include <string> #include <vector> #include <iostream> const std::string kSharedMemoryFileName("./MySharedMemory.txt"); const std::size_t kSharedMemorySize = 33; const std::string kSharedMemoryName("MyTest"); class ServerTask: public Poco::Task { public: ServerTask() : Poco::Task("ServerTask") { Poco::Path path(kSharedMemoryFileName); m_File = Poco::File(path); if(!m_File.exists()) { m_File.createFile(); Poco::FileOutputStream ostr(m_File.path()); for(std::size_t i=0; i<kSharedMemorySize; ++i) { ostr << ' '; } } } ~ServerTask() { if(m_File.exists()) { m_File.remove(); } } void runTask() { Poco::Logger& logger = Poco::Util::Application::instance().logger(); #if (0x01040100 <= POCO_VERSION) Poco::SharedMemory sharedMemoryNamed(kSharedMemoryName, kSharedMemorySize, Poco::SharedMemory::AM_WRITE, 0, true); #endif std::size_t loopCount = 0; while(!sleep(300)) // Poco::Task::sleep() should be called in favor of Thread::sleep() { Poco::SharedMemory sharedMemory(m_File, Poco::SharedMemory::AM_WRITE); for(std::size_t i=0; i<kSharedMemorySize; ++i) { sharedMemory.begin()[i] = static_cast<char>(('A' + loopCount + i) & 0x7F); } logger.information(Poco::format("ServerTask: %c - %c" , sharedMemory.begin()[0] , sharedMemory.end()[-1])); #if (0x01040100 <= POCO_VERSION) for(std::size_t i=0; i<kSharedMemorySize; ++i) { sharedMemoryNamed.begin()[i] = static_cast<char>(('A' + loopCount + i) & 0x7F); } logger.information(Poco::format("ServerTask: %c - %c (named)" , sharedMemoryNamed.begin()[0] , sharedMemoryNamed.end()[-1])); #endif ++loopCount; } } private: Poco::File m_File; }; class SharedMemoryServer: public Poco::Util::ServerApplication { public: SharedMemoryServer() { } protected: void initialize(Application& self) { loadConfiguration(); // load default configuration files, if present Poco::Util::ServerApplication::initialize(self); logger().information("SharedMemoryServer starting up"); } void uninitialize() { logger().information("SharedMemoryServer shutting down"); Poco::Util::ServerApplication::uninitialize(); } int main(const std::vector<std::string>& args) { Poco::TaskManager tm; tm.start(new ServerTask); waitForTerminationRequest(); tm.cancelAll(); tm.joinAll(); return Application::EXIT_OK; } }; POCO_SERVER_MAIN(SharedMemoryServer) |
SharedMemoryClient.cpp
・Shared Memory のクライアント。
・Poco::Util::ServerApplication を使用。
・ClientTask を立ち上げ、その中で周期的に Shared Memory の内容を読み出し。
・最後の行の POCO_SERVER_MAIN は、その中に main() エントリーポイントがあるマクロ。
(Util/include/Poco/Util/ServerApplication.h 参照)
#include <Poco/Util/ServerApplication.h> #include <Poco/Task.h> #include <Poco/TaskManager.h> #include <Poco/SharedMemory.h> #include <Poco/Format.h> #include <Poco/Path.h> #include <Poco/File.h> #ifndef POCO_VERSION #include <Poco/Version.h> #endif #include <string> #include <vector> #include <iostream> const std::string kSharedMemoryFileName("./MySharedMemory.txt"); const std::size_t kSharedMemorySize = 33; const std::string kSharedMemoryName("MyTest"); class ClientTask: public Poco::Task { public: ClientTask() : Poco::Task("ClientTask") { Poco::Path path(kSharedMemoryFileName); m_File = Poco::File(path); } void runTask() { Poco::Logger& logger = Poco::Util::Application::instance().logger(); #if (0x01040100 <= POCO_VERSION) Poco::SharedMemory sharedMemoryNamed(kSharedMemoryName, kSharedMemorySize, Poco::SharedMemory::AM_READ, 0, false); #endif while(!sleep(300)) // Poco::Task::sleep() should be called in favor of Thread::sleep() { Poco::SharedMemory sharedMemory(m_File, Poco::SharedMemory::AM_READ); logger.information(Poco::format("ClientTask: %c - %c" , sharedMemory.begin()[0] , sharedMemory.end()[-1])); #if (0x01040100 <= POCO_VERSION) logger.information(Poco::format("ClientTask: %c - %c (named)" , sharedMemoryNamed.begin()[0] , sharedMemoryNamed.end()[-1])); #endif } } private: Poco::File m_File; }; class SharedMemoryClient: public Poco::Util::ServerApplication { public: SharedMemoryClient() { } protected: void initialize(Application& self) { loadConfiguration(); // load default configuration files, if present Poco::Util::ServerApplication::initialize(self); logger().information("SharedMemoryClient starting up"); } void uninitialize() { logger().information("SharedMemoryClient shutting down"); Poco::Util::ServerApplication::uninitialize(); } int main(const std::vector<std::string>& args) { Poco::TaskManager tm; tm.start(new ClientTask); waitForTerminationRequest(); tm.cancelAll(); tm.joinAll(); return Application::EXIT_OK; } }; POCO_SERVER_MAIN(SharedMemoryClient) |
SharedMemoryTest.cpp
・Shared Memory のサーバーとクライアントプロセスを起動し、しばらく待った後にそれぞれを終了。
#include <Poco/Process.h> #include <Poco/Pipe.h> #include <Poco/PipeStream.h> #include <Poco/StreamCopier.h> #include <Poco/Format.h> #include <Poco/Runnable.h> #include <Poco/Thread.h> #include <string> #include <vector> #include <iostream> #include "ScopedLogMessage.h" #include "PrepareConsoleLogger.h" #if defined(POCO_OS_FAMILY_WINDOWS) const std::string kCommandTable[] = {"SharedMemoryTestServer.exe", "SharedMemoryTestClient.exe"}; #else const std::string kCommandTable[] = {"./SharedMemoryTestServer", "./SharedMemoryTestClient"}; #endif const std::size_t kNumCommands = sizeof(kCommandTable)/sizeof(kCommandTable[0]); class ProcessLauncher: public Poco::Runnable { public: ProcessLauncher(ScopedLogMessage& msg, const std::string& command) : m_msg(msg) , m_command(command) , m_pPh(NULL) , m_Pid(0) { } ~ProcessLauncher() { int rc = m_pPh->wait(); m_msg.Message(Poco::format(" \"%s\" terminated with return code = %d", m_command, rc)); delete m_pPh; } void run() { m_msg.Message(Poco::format(" launch \"%s\"", m_command)); std::vector<std::string> args; Poco::Pipe outPipe; m_pPh = new Poco::ProcessHandle(Poco::Process::launch(m_command, args, 0, &outPipe, 0)); m_Pid = m_pPh->id(); Poco::PipeInputStream istr(outPipe); Poco::StreamCopier::copyStream(istr, std::cout); } void stop() { m_msg.Message(Poco::format(" \"%s\" requestTermination", m_command)); Poco::Process::requestTermination(m_Pid); } private: ScopedLogMessage& m_msg; const std::string& m_command; Poco::ProcessHandle* m_pPh; Poco::Process::PID m_Pid; }; int main(int /*argc*/, char** /*argv*/) { PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION); ScopedLogMessage msg("SharedMemoryTest ", "start", "end"); Poco::Thread thread[kNumCommands]; ProcessLauncher* pLauncher[kNumCommands]; for(std::size_t i=0; i<kNumCommands; ++i) { pLauncher[i] = new ProcessLauncher(msg, kCommandTable[i]); thread[i].start(*pLauncher[i]); Poco::Thread::sleep(200); } Poco::Thread::sleep(2000); for(std::size_t i=0; i<kNumCommands; ++i) { std::size_t index = kNumCommands-1-i; pLauncher[index]->stop(); thread[index].join(); delete pLauncher[index]; } return 0; } |
Results of execution
・On Linux and Macintosh OSX 10.6.4
[0] SharedMemoryTest start [1] launch "./SharedMemoryTestServer" SharedMemoryServer starting up [2] launch "./SharedMemoryTestClient" SharedMemoryClient starting up ServerTask: A - a ServerTask: A - a (named) ClientTask: A - a ClientTask: A - a (named) ServerTask: B - b ServerTask: B - b (named) ClientTask: B - b ClientTask: B - b (named) ServerTask: C - c ServerTask: C - c (named) ClientTask: C - c ClientTask: C - c (named) ServerTask: D - d ServerTask: D - d (named) ClientTask: D - d ClientTask: D - d (named) ServerTask: E - e ServerTask: E - e (named) ClientTask: E - e ClientTask: E - e (named) ServerTask: F - f ServerTask: F - f (named) ClientTask: F - f ClientTask: F - f (named) ServerTask: G - g ServerTask: G - g (named) ClientTask: G - g ClientTask: G - g (named) [0] "./SharedMemoryTestClient" requestTermination SharedMemoryClient shutting down [0] "./SharedMemoryTestClient" terminated with return code = 0 [0] "./SharedMemoryTestServer" requestTermination SharedMemoryServer shutting down [0] "./SharedMemoryTestServer" terminated with return code = 0 [0] SharedMemoryTest end |
・On Windows XP sp3
[0] SharedMemoryTest start [1] launch "SharedMemoryTestServer.exe" SharedMemoryServer starting up [2] launch "SharedMemoryTestClient.exe" SharedMemoryClient starting up ServerTask: A - a ServerTask: A - a (named) ClientTask: A - a ClientTask: A - a (named) ServerTask: B - b ServerTask: B - b (named) ClientTask: B - b ClientTask: B - b (named) ServerTask: C - c ServerTask: C - c (named) ClientTask: C - c ClientTask: C - c (named) ServerTask: D - d ServerTask: D - d (named) ClientTask: D - d ClientTask: D - d (named) ServerTask: E - e ServerTask: E - e (named) ClientTask: E - e ClientTask: E - e (named) ServerTask: F - f ServerTask: F - f (named) ClientTask: F - f ClientTask: F - f (named) ServerTask: G - g ServerTask: G - g (named) ClientTask: G - g ClientTask: G - g (named) [0] "SharedMemoryTestClient.exe" requestTermination SharedMemoryClient shutting down [0] "SharedMemoryTestClient.exe" terminated with return code = 0 [0] "SharedMemoryTestServer.exe" requestTermination SharedMemoryServer shutting down [0] "SharedMemoryTestServer.exe" terminated with return code = 0 [0] SharedMemoryTest end |
Downloads
・ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年6月29日からのダウンロード数:1304
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
Reference
・http://pocoproject.org にある Processes のプレセンテーション。(PDF)
![]() |
Copyright © 2010 Round Square Inc. All rights reserved. |
---|