概要
Producer-Consumerパターン
詳細
生産者はデータを作成するスレッド。
消費者はデータを利用するスレッド。
生産者、消費者はどちらも1〜N存在します。
両者の間に橋渡し役を用意します。
生産者と消費者が1対1の場合はPipeパターンとも呼びます。
サンプル
仕様
かんばんを利用したアジャイル開発を想定します。
システム開発会社の「株式会社れいほうシステム」ではオンサイト顧客、かんばんを実践しています。
開発現場に顧客である「株式会社ねっけつ商事」の担当者5名に常駐してもらい、要件を聞くとすぐに
開発出来る体制をとっています。
かんばんはTODO(未着手)、Done(完了)の2ステータスを可視化します。
※問題簡易化のため作業を開始したら一瞬で完了するものとします。
・顧客である「株式会社ねっけつ商事」の担当者は仕様をストーリーカードに記述してかんばんのTODOに貼り付けます。
ストーリーにはタイトルが記載されます。
・顧客が一度に依頼出来るストーリーは5件まで。
ねっけつ商事はれいほうシステムが恐ろしくて5件以上の要件を発注出来ません。
5件依頼中の場合は、依頼可能になるまで待機します。
=>Guarded Suspensionパターンを使用
・開発者はかんばんからストーリーカードを取得して開発します。
取得対象がない場合は待機します。
=>Guarded Suspensionパターンを使用
データ(Data)=>ストーリーカード
生産者(Producer)=>顧客
消費者(Consumer)=>開発者
通路役(Channel)=>かんばん
ソースコード
# encoding: utf-8 require "pp" require "thread" module Status TODO = 0 DONE = 2 end class StoryCard attr_accessor :id, :subject, :status def initialize(subject) @subject, @status = subject, Status::TODO end end class Kanban attr_accessor :todo_story_cards, :done_story_cards, :count MAX_CARDS = 5 def initialize @m = Mutex.new @c = ConditionVariable.new @count = 0 @todo_story_cards, @doing_story_cards, @done_story_cards = [],[],[] end def append(story_card, name) @m.synchronize { while max? do puts "waiting..." @c.wait @m end @count += 1 story_card.id = @count @todo_story_cards << story_card puts "#{name} append story card #{story_card.inspect}" @c.signal } end def pull @m.synchronize { loop do @todo_story_cards.each do |c| @todo_story_cards.delete c c.status = Status::DONE @done_story_cards << c @c.signal return c end @c.wait @m end } end private def max? active_count >= MAX_CARDS end def active_count @todo_story_cards.size end end class Customer < Thread attr_accessor :name, :kanban def initialize(name, kanban) block = lambda { @m = Mutex.new @name = name @kanban = kanban 5.times {request} } super(&block) end def request sleep (rand 5) * 0.1 story_card = StoryCard.new("spec") @kanban.append story_card, @name end end class Developer < Thread attr_accessor :name, :kanban def initialize(name, kanban) block = lambda { @name, @kanban = name, kanban 5.times {develop} } super(&block) end def develop sleep (rand 5) * 0.1 card = @kanban.pull puts "#{name} pull #{card.inspect}" end end kanban = Kanban.new threads = [] threads << Customer.new("くにお", kanban) threads << Customer.new("すがた", kanban) threads << Customer.new("いちじょう", kanban) threads << Customer.new("もりもと", kanban) threads << Customer.new("ななせ", kanban) threads << Developer.new("りゅういち", kanban) threads << Developer.new("りゅうじ", kanban) threads << Developer.new("もちづき",kanban) threads << Developer.new("こばやし", kanban) threads << Developer.new("はやさか", kanban) threads.each {|t|t.join}
実行結果例
ななせ append story card #<StoryCard:0x6043c8 @subject="spec", @status=0, @id=1> はやさか pull #<StoryCard:0x6043c8 @subject="spec", @status=2, @id=1> いちじょう append story card #<StoryCard:0x5f78e8 @subject="spec", @status=0, @id=2> こばやし pull #<StoryCard:0x5f78e8 @subject="spec", @status=2, @id=2> くにお append story card #<StoryCard:0x5f7600 @subject="spec", @status=0, @id=3> りゅうじ pull #<StoryCard:0x5f7600 @subject="spec", @status=2, @id=3> くにお append story card #<StoryCard:0x5f7378 @subject="spec", @status=0, @id=4> りゅういち pull #<StoryCard:0x5f7378 @subject="spec", @status=2, @id=4> すがた append story card #<StoryCard:0x5f7120 @subject="spec", @status=0, @id=5> こばやし pull #<StoryCard:0x5f7120 @subject="spec", @status=2, @id=5> ななせ append story card #<StoryCard:0x5f6ee0 @subject="spec", @status=0, @id=6> もちづき pull #<StoryCard:0x5f6ee0 @subject="spec", @status=2, @id=6> くにお append story card #<StoryCard:0x5f6ca0 @subject="spec", @status=0, @id=7> もりもと append story card #<StoryCard:0x5f6b80 @subject="spec", @status=0, @id=8> はやさか pull #<StoryCard:0x5f6ca0 @subject="spec", @status=2, @id=7> こばやし pull #<StoryCard:0x5f6b80 @subject="spec", @status=2, @id=8> いちじょう append story card #<StoryCard:0x5f6808 @subject="spec", @status=0, @id=9> りゅうじ pull #<StoryCard:0x5f6808 @subject="spec", @status=2, @id=9> すがた append story card #<StoryCard:0x5f65c8 @subject="spec", @status=0, @id=10> すがた append story card #<StoryCard:0x5f64a8 @subject="spec", @status=0, @id=11> もちづき pull #<StoryCard:0x5f65c8 @subject="spec", @status=2, @id=10> ななせ append story card #<StoryCard:0x5f6250 @subject="spec", @status=0, @id=12> くにお append story card #<StoryCard:0x5f6130 @subject="spec", @status=0, @id=13> りゅうじ pull #<StoryCard:0x5f64a8 @subject="spec", @status=2, @id=11> もりもと append story card #<StoryCard:0x5f5ef0 @subject="spec", @status=0, @id=14> りゅうじ pull #<StoryCard:0x5f6250 @subject="spec", @status=2, @id=12> りゅういち pull #<StoryCard:0x5f6130 @subject="spec", @status=2, @id=13> くにお append story card #<StoryCard:0x5f5b90 @subject="spec", @status=0, @id=15> すがた append story card #<StoryCard:0x5f5a58 @subject="spec", @status=0, @id=16> すがた append story card #<StoryCard:0x5f5920 @subject="spec", @status=0, @id=17> いちじょう append story card #<StoryCard:0x5f57e8 @subject="spec", @status=0, @id=18> はやさか pull #<StoryCard:0x5f5ef0 @subject="spec", @status=2, @id=14> いちじょう append story card #<StoryCard:0x5f55c0 @subject="spec", @status=0, @id=19> waiting... もちづき pull #<StoryCard:0x5f5b90 @subject="spec", @status=2, @id=15> こばやし pull #<StoryCard:0x5f5a58 @subject="spec", @status=2, @id=16> ななせ append story card #<StoryCard:0x5f51b8 @subject="spec", @status=0, @id=20> いちじょう append story card #<StoryCard:0x5f5488 @subject="spec", @status=0, @id=21> waiting... はやさか pull #<StoryCard:0x5f5920 @subject="spec", @status=2, @id=17> りゅうじ pull #<StoryCard:0x5f57e8 @subject="spec", @status=2, @id=18> りゅういち pull #<StoryCard:0x5f55c0 @subject="spec", @status=2, @id=19> ななせ append story card #<StoryCard:0x5f4f90 @subject="spec", @status=0, @id=22> こばやし pull #<StoryCard:0x5f51b8 @subject="spec", @status=2, @id=20> もりもと append story card #<StoryCard:0x5f4a50 @subject="spec", @status=0, @id=23> もちづき pull #<StoryCard:0x5f5488 @subject="spec", @status=2, @id=21> もちづき pull #<StoryCard:0x5f4f90 @subject="spec", @status=2, @id=22> りゅういち pull #<StoryCard:0x5f4a50 @subject="spec", @status=2, @id=23> もりもと append story card #<StoryCard:0x5f4618 @subject="spec", @status=0, @id=24> はやさか pull #<StoryCard:0x5f4618 @subject="spec", @status=2, @id=24> もりもと append story card #<StoryCard:0x5f43d8 @subject="spec", @status=0, @id=25> りゅういち pull #<StoryCard:0x5f43d8 @subject="spec", @status=2, @id=25>