fc2ブログ

[C++] Consumer-Producerパターン

2013-04-15 | 11:19

このページにあるConsumer-ProducerパターンのサンプルプログラムをC++で書いてみた。

#include <stdio.h>
#include <iostream>
#include <string>

#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

class Table {
    public:
        void put(const std::string& food) {
            boost::mutex::scoped_lock l(m_);
            while (!food_on_table_.empty()) {
                std::cout << boost::this_thread::get_id() << " waits (put)" << std::endl;
                c_.wait(l);
            }
            std::cout << boost::this_thread::get_id() << " puts" << std::endl;
            food_on_table_ = food;
            heavyJob();
            std::cout << food_on_table_ << " is on the table. >>>>>>>>>>" << std::endl;
            c_.notify_all();
        }
        std::string eat() {
            boost::mutex::scoped_lock l(m_);
            while (food_on_table_.empty()) {
                std::cout << boost::this_thread::get_id() << " waits (eat)" << std::endl;
                c_.wait(l);
            }
            std::string food = food_on_table_;
            std::cout << boost::this_thread::get_id() << " eats " << food << " <<<<<<<<<<" << std::endl;
            food_on_table_ = "";
            heavyJob();
            std::cout << "Nothing is on the table." << std::endl;
            c_.notify_all();
            return food;
        }

    private:
        void heavyJob() {
            int msec = 3000*(rand()/(double)RAND_MAX);
            std::cout << msec << "msec sleep" << std::endl;
            boost::this_thread::sleep(boost::posix_time::milliseconds(3000*(rand()/(double)RAND_MAX)));
            std::cout << "wake up" << std::endl;
        }

        boost::mutex m_;
        boost::condition_variable c_;
        std::string food_on_table_;
};

class Producer {
    public:
        Producer(const std::string& food, Table* table):counter_(0) {
            table_ = table;
            food_ = food;
        }
        void run() {
            while (true) {
                table_->put(food_ + " No." + boost::lexical_cast<std::string>(counter_));
                counter_++;
            }
        }

    private :
        int counter_;
        Table* table_;
        std::string food_;
};

class Consumer {
    public:
        Consumer(Table* table) {
            table_ = table;
        }
        void run() {
            while (true) {
                table_->eat();
            }
        }
    private:
        Table* table_;
};

int main(){
    Table table;
    Producer p1("Apple", &table);
    Producer p2("Banana", &table);
    Producer p3("Banana", &table);
    Consumer c1(&table);
    Consumer c2(&table);

    boost::thread_group g;
    g.create_thread(boost::bind(&Producer::run, &p1));
    g.create_thread(boost::bind(&Producer::run, &p2));
    g.create_thread(boost::bind(&Producer::run, &p3));
    g.create_thread(boost::bind(&Consumer::run, &c1));
    g.create_thread(boost::bind(&Consumer::run, &c2));

    g.join_all();
}

注意点

notify_all()によってwaitしているスレッドが動き出すのは、notify_all()を実行した直後ではなく、mutexがリリースされた直後である。参照

スポンサーサイト



Comment

Post a comment

Secret