Balking
適切な状態になっていないなら処理を中断する、というパターン。
以下は増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編のサンプルを Boost.Thread を使って書いたコード。
save, doSave メソッドは Thread#currentThread を必要としていたんだけど、boost::thread にはそんなのは無いので this を渡して無理矢理名前を取得しています。
最初は TSS を使ってカレントスレッドを取得していたんだけど、何か冗長になってきたので上記の方法に変更してみました。
data.h
#ifndef MTDP_BALKING_DATA_H_INCLUDED #define MTDP_BALKING_DATA_H_INCLUDED #include <boost/thread.hpp> #include <string> #include <iostream> #include <fstream> #include "../thread_helper.h" namespace mtdp{ namespace balking { class data { private: const std::string filename_; // 保存するファイルの名前 std::string content_; // データの内容 bool changed_; // 変更した内容が保存されていないなら true boost::mutex mutex_; public: data(std::string filename, std::string content) : filename_(filename), content_(content), changed_(true) { } // データの内容を書き換える void change(std::string newContent) { boost::mutex::scoped_lock lock(mutex_); content_ = newContent; changed_ = true; } // データの内容が変更されていたらファイルに保存する template<class TThread> void save(TThread* p) { boost::mutex::scoped_lock lock(mutex_); if (!changed_) { return; } doSave(p); changed_ = false; } private: // データの内容を実際にファイルに保存する template<class TThread> void doSave(TThread* p) { thread_helper::shared_cout(p->name() + " calls doSave, content = " + content_ + "\n"); std::fstream fs(filename_.c_str(), std::ios_base::out); fs << (content_ + "\n"); } }; }} #endif // MTDP_BALKING_DATA_H_INCLUDED
saver_thread.h
#ifndef MTDP_BALKING_SAVER_THREAD_H_INCLUDED #define MTDP_BALKING_SAVER_THREAD_H_INCLUDED #include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <string.h> #include "data.h" #include "../thread_helper.h" namespace mtdp{ namespace balking { class saver_thread { private: const std::string name_; const boost::shared_ptr<data> data_; public: saver_thread(const std::string& name, boost::shared_ptr<data> d) : name_(name), data_(d) { } void run() { while (true) { data_->save(this); thread_helper::sleep(1000); } } std::string name() const { return name_; } }; }} #endif // MTDP_BALKING_SAVER_THREAD_H_INCLUDED
changer_thread.h
#ifndef MTDP_BALKING_CHANGER_THREAD_H_INCLUDED #define MTDP_BALKING_CHANGER_THREAD_H_INCLUDED #include <boost/shared_ptr.hpp> #include <boost/random.hpp> #include <string> #include "data.h" #include "../thread_helper.h" namespace mtdp{ namespace balking { class changer_thread { private: const std::string name_; const boost::shared_ptr<data> data_; const boost::mt19937 mt_; public: changer_thread(std::string name, boost::shared_ptr<data> d) : name_(name), data_(d) { } void run() { boost::variate_generator<boost::mt19937, boost::uniform_int<> > random(mt_, boost::uniform_int<>(0, 1000)); for (int i = 0; true; i++) { data_->change("No." + to_string(i)); // データを変更する thread_helper::sleep(random()); // 仕事のつもり data_->save(this); // 明示的に保存する } } std::string name() const { return name_; } }; }} #endif // MTDP_BALKING_CHANGER_THREAD_H_INCLUDED
main.cpp
#include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> #include "data.h" #include "saver_thread.h" #include "changer_thread.h" namespace mtdp{ namespace balking { void main() { boost::shared_ptr<data> d(new data("data.txt", "(empty)")); boost::thread_group group; group.create_thread(boost::bind(&changer_thread::run, boost::shared_ptr<changer_thread>(new changer_thread("ChangerThread", d)))); group.create_thread(boost::bind(&saver_thread::run, boost::shared_ptr<saver_thread>(new saver_thread("SaverThread", d)))); group.join_all(); } }}