Thread-Specific Storage
スレッド固有の領域を扱うパターン。
Boost.Thread には boost::thread_specific_ptr というクラスがあるので、これを使えば実現できる。
以下は増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編のサンプルを Boost.Thread を使って書いたコード。
ts_log.h
#ifndef MTDP_THREAD_SPECIFIC_STORAGE_TS_LOG_H_INCLUDED #define MTDP_THREAD_SPECIFIC_STORAGE_TS_LOG_H_INCLUDED #include <fstream> #include <string> namespace mtdp{ namespace thread_specific_storage { class ts_log { private: std::fstream fs_; public: ts_log(const std::string& filename) : fs_(filename.c_str(), std::ios_base::out) { } // ログを書く void println(const std::string& s) { fs_ << s << std::endl; } // ログを閉じる void close() { fs_ << "==== End of log ====" << std::endl; fs_.close(); } }; }} #endif // MTDP_THREAD_SPECIFIC_STORAGE_TS_LOG_H_INCLUDED
log.h
#ifndef MTDP_THREAD_SPECIFIC_STORAGE_LOG_H_INCLUDED #define MTDP_THREAD_SPECIFIC_STORAGE_LOG_H_INCLUDED #include <boost/thread.hpp> #include <fstream> #include <string> #include "ts_log.h" namespace mtdp{ namespace thread_specific_storage { class simple_log { private: struct instance { std::fstream fs_; instance() : fs_("log.txt", std::ios_base::out) { } ~instance() { fs_.close(); } }; static instance& get() { static instance inst; return inst; } public: // ログを書く static void println(std::string s) { get().fs_ << s << std::endl; } // ログを閉じる static void close() { get().fs_ << "==== End of log ====" << std::endl; get().fs_.close(); } }; class log { public: // ログを書く template<class T> static void println(T* p, std::string s) { get_ts_log(p)->println(s); } // ログを閉じる template<class T> static void close(T* p) { get_ts_log(p)->close(); } private: // スレッド固有のログを得る template<class T> static ts_log* get_ts_log(T* p) { static boost::thread_specific_ptr<ts_log> tss_log; ts_log* tl = tss_log.get(); if (tl == 0) { tl = new ts_log(p->name() + "-log.txt"); tss_log.reset(tl); } return tl; } }; }} #endif // MTDP_THREAD_SPECIFIC_STORAGE_LOG_H_INCLUDED
client_thread.h
#ifndef MTDP_THREAD_SPECIFIC_STRAGE_CLIENT_THREAD_H_INCLUDED #define MTDP_THREAD_SPECIFIC_STRAGE_CLIENT_THREAD_H_INCLUDED #include <string> #include "log.h" #include "../thread_helper.h" namespace mtdp{ namespace thread_specific_storage { class client_thread { private: std::string name_; public: client_thread(std::string name) : name_(name) { } void run() { thread_helper::shared_cout(name() + " BEGIN\n"); for (int i = 0; i < 10; i++) { log::println(this, "i = " + to_string(i)); thread_helper::sleep(100); } log::close(this); thread_helper::shared_cout(name() + " BEGIN\n"); } std::string name() { return name_; } }; }} #endif // MTDP_THREAD_SPECIFIC_STRAGE_CLIENT_THREAD_H_INCLUDED
main.cpp
#include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> #include <iostream> #include "log.h" #include "client_thread.h" #include "../thread_helper.h" namespace mtdp{ namespace thread_specific_storage { void main_single() { std::cout << "BEGIN" << std::endl; for (int i = 0; i < 10; i++) { simple_log::println("main: i = " + to_string(i)); thread_helper::sleep(100); } simple_log::close(); std::cout << "END" << std::endl; } void main_multi() { boost::thread_group group; group.create_thread(boost::bind(&client_thread::run, boost::shared_ptr<client_thread>(new client_thread("Alice")))); group.create_thread(boost::bind(&client_thread::run, boost::shared_ptr<client_thread>(new client_thread("Bobby")))); group.create_thread(boost::bind(&client_thread::run, boost::shared_ptr<client_thread>(new client_thread("Chris")))); group.join_all(); } void main() { // main_single(); // ↑シングルスレッド用のサンプルはこっち main_multi(); // ↑マルチスレッド用のサンプルはこっち } }}