Guarded Suspension
適切な状態になっていないならスレッドを待たせる、というパターン。
boost::condition を使って実現することが出来る。
以下は増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編のサンプルを Boost.Thread を使って書いたコード。
request.h
#ifndef MTDP_GUARDED_SUSPENSION_REQUEST_H_INCLUDED #define MTDP_GUARDED_SUSPENSION_REQUEST_H_INCLUDED #include <string> namespace mtdp{ namespace guarded_suspension { class request { private: const std::string name_; public: request(std::string name) : name_(name) { } std::string name() { return name_; } std::string to_string() { return "[ Request " + name_ + " ]"; } }; }} #endif // MTDP_GUARDED_SUSPENSION_REQUEST_H_INCLUDED
request_queue.h
#ifndef MTDP_GUARDED_SUSPENSION_REQUEST_QUEUE_H_INCLUDED #define MTDP_GUARDED_SUSPENSION_REQUEST_QUEUE_H_INCLUDED #include <boost/shared_ptr.hpp> #include <boost/thread.hpp> #include <queue> #include "request.h" namespace mtdp{ namespace guarded_suspension { class request_queue { private: std::queue<boost::shared_ptr<request> > queue_; boost::mutex mutex_; boost::condition condition_; public: boost::shared_ptr<request> get_request() { boost::mutex::scoped_lock lock(mutex_); while (queue_.empty()) { condition_.wait(lock); } // ↓こんな風に書くことも出来る // condition_.wait(lock, !boost::bind(&std::queue<boost::shared_ptr<request> >::empty, &queue_)); boost::shared_ptr<request> r = queue_.front(); queue_.pop(); return r; } void put_request(boost::shared_ptr<request> r) { boost::mutex::scoped_lock lock(mutex_); queue_.push(r); condition_.notify_all(); } }; }} #endif // MTDP_GUARDED_SUSPENSION_REQUEST_QUEUE_H_INCLUDED
client_thread.h
#ifndef MTDP_GUARDED_SUSPENSION_CLIENT_THREAD_H_INCLUDED #define MTDP_GUARDED_SUSPENSION_CLIENT_THREAD_H_INCLUDED #include <boost/random.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <string> #include "request_queue.h" #include "../thread_helper.h" namespace mtdp{ namespace guarded_suspension { class client_thread { private: const std::string name_; const boost::shared_ptr<request_queue> request_queue_; const boost::mt19937 mt_; public: client_thread(boost::shared_ptr<request_queue> rq, std::string name, boost::uint32_t seed) : name_(name), request_queue_(rq), mt_(seed) { } void run() { boost::variate_generator<boost::mt19937, boost::uniform_int<> > random(mt_, boost::uniform_int<>(0, 1000)); for (int i = 0; i < 10000; i++) { boost::shared_ptr<request> r = request_queue_->get_request(); thread_helper::shared_cout(name_ + " handles " + r->to_string() + "\n"); thread_helper::sleep(random()); } } }; }} #endif // MTDP_GUARDED_SUSPENSION_CLIENT_THREAD_H_INCLUDED
server_thread.h
#ifndef MTDP_GUARDED_SUSPENSION_SERVER_THREAD_H_INCLUDED #define MTDP_GUARDED_SUSPENSION_SERVER_THREAD_H_INCLUDED #include <boost/random.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <string> #include "request_queue.h" #include "../thread_helper.h" namespace mtdp{ namespace guarded_suspension { class server_thread { private: const std::string name_; const boost::shared_ptr<request_queue> request_queue_; const boost::mt19937 mt_; public: server_thread(boost::shared_ptr<request_queue> rq, std::string name, boost::uint32_t seed) : name_(name), request_queue_(rq), mt_(seed) { } void run() { boost::variate_generator<boost::mt19937, boost::uniform_int<> > random(mt_, boost::uniform_int<>(0, 1000)); for (int i = 0; i < 10000; i++) { boost::shared_ptr<request> r(new request("No." + to_string(i))); thread_helper::shared_cout(name_ + " requests " + r->to_string() + "\n"); request_queue_->put_request(r); thread_helper::sleep(random()); } } }; }} #endif // MTDP_GUARDED_SUSPENSION_SERVER_THREAD_H_INCLUDED
main.cpp
#include <boost/thread.hpp> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include "request_queue.h" #include "client_thread.h" #include "server_thread.h" namespace mtdp{ namespace guarded_suspension { void main() { boost::shared_ptr<request_queue> rq(new request_queue()); boost::thread_group group; group.create_thread(boost::bind(&client_thread::run, boost::shared_ptr<client_thread>(new client_thread(rq, "Alice", 3141592)))); group.create_thread(boost::bind(&server_thread::run, boost::shared_ptr<server_thread>(new server_thread(rq, "Bobby", 6535897)))); group.join_all(); } }}