Single Threaded Execution


同時に実行できるスレッドを1つだけにするパターン。
boost::mutex と boost::mutex::scoped_lock を使えばいい。


以下は増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編のサンプルを Boost.Thread を使って書いたコード。


main.cpp

#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include "gate.h"
#include "user_thread.h"

namespace mtdp { namespace single_threaded_execution
{
    void main()
    {
        boost::shared_ptr<gate> g(new gate());

        boost::thread_group group;
        group.create_thread(boost::bind(&user_thread::run, boost::shared_ptr<user_thread>(new user_thread(g, "Alice", "Alaska"))));
        group.create_thread(boost::bind(&user_thread::run, boost::shared_ptr<user_thread>(new user_thread(g, "Bobby", "Brazil"))));
        group.create_thread(boost::bind(&user_thread::run, boost::shared_ptr<user_thread>(new user_thread(g, "Chris", "Canada"))));
        group.join_all();
    }
}}

gate.h

#ifndef MTDP_SINGLE_THREADED_EXECUTION_GATE_H_INCLUDED
#define MTDP_SINGLE_THREADED_EXECUTION_GATE_H_INCLUDED

#include <string>
#include <iostream>
#include "../thread_helper.h"

namespace mtdp{ namespace single_threaded_execution
{

class bad_gate
{
private:
    int counter_;
    std::string name_;
    std::string address_;

public:
    bad_gate() : counter_(0), name_("Nobody"), address_("Nowhere")
    {
    }

    void pass(std::string name, std::string address)
    {
        counter_++;
        name_ = name;
        address_ = address;
        check();
    }
    std::string to_string()
    {
        return "No." + mtdp::to_string(counter_) + ": " + name_ + ", " + address_;
    }

private:
    void check()
    {
        if (name_[0] != address_[0])
        {
            thread_helper::shared_cout("***** BROKEN ***** " + to_string() + "\n");
        }
    }
};

class good_gate
{
private:
    int counter_;
    std::string name_;
    std::string address_;

    boost::mutex mutex_;

public:
    good_gate() : counter_(0), name_("Nobody"), address_("Nowhere")
    {
    }

    void pass(std::string name, std::string address)
    {
        boost::mutex::scoped_lock lock(mutex_);

        counter_++;
        name_ = name;
        address_ = address;
        check();
    }
    std::string to_string()
    {
        return "No." + mtdp::to_string(counter_) + ": " + name_ + ", " + address_;
    }

private:
    void check()
    {
        if (name_[0] != address_[0])
        {
            thread_helper::shared_cout("***** BROKEN ***** " + to_string() + "\n");
        }
    }
};

// これを変更して bad_gate と good_gate を切り替える
typedef good_gate gate;

}}

#endif // MTDP_SINGLE_THREADED_EXECUTION_GATE_H_INCLUDED

user_thread.h

#ifndef MTDP_SINGLE_THREADED_EXECUTION_USER_THREAD_H_INCLUDED
#define MTDP_SINGLE_THREADED_EXECUTION_USER_THREAD_H_INCLUDED

#include <boost/shared_ptr.hpp>
#include "gate.h"
#include "../thread_helper.h"

namespace mtdp{ namespace single_threaded_execution
{

class user_thread
{
private:
    boost::shared_ptr<gate> gate_;
    std::string myname_;
    std::string myaddress_;

public:
    user_thread(boost::shared_ptr<gate> g, std::string myname, std::string myaddress)
    {
        gate_ = g;
        myname_ = myname;
        myaddress_ = myaddress;
    }
    void run()
    {
        thread_helper::shared_cout(myname_ + " BEGIN\n");
        while (true)
        {
            gate_->pass(myname_, myaddress_);
        }
    }
};

}}

#endif // MTDP_SINGLE_THREADED_EXECUTION_USER_THREAD_H_INCLUDED