1#!/usr/local/bin/ruby 2# TupleSpace 3# Copyright (c) 1999-2000 Masatoshi SEKI 4# You can redistribute it and/or modify it under the same terms as Ruby. 5 6require 'thread' 7 8class TupleSpace 9 class Template 10 def initialize(list) 11 @list = list 12 @check_idx = [] 13 @list.each_with_index do |x, i| 14 @check_idx.push i if x 15 end 16 @size = @list.size 17 end 18 19 attr :size 20 alias length size 21 22 def match(tuple) 23 return nil if tuple.size != self.size 24 @check_idx.each do |i| 25 unless @list[i] === tuple[i] 26 return false 27 end 28 end 29 return true 30 end 31 end 32 33 def initialize 34 @que = {} 35 @waiting = {} 36 @que.taint # enable tainted comunication 37 @waiting.taint 38 self.taint 39 end 40 41 def wakeup_waiting(tuple) 42 sz = tuple.length 43 return nil unless @waiting[sz] 44 45 x = nil 46 i = -1 47 found = false 48 @waiting[sz] = @waiting[sz].find_all { |x| 49 if x[0].match(tuple) 50 begin 51 x[1].wakeup 52 rescue ThreadError 53 end 54 false 55 else 56 true 57 end 58 } 59 end 60 61 def put_waiting(template, thread) 62 sz = template.length 63 @waiting[sz] = [] unless @waiting[sz] 64 @waiting[sz].push([Template.new(template), thread]) 65 end 66 private :wakeup_waiting 67 private :put_waiting 68 69 def get_que(template) 70 sz = template.length 71 return nil unless @que[sz] 72 73 template = Template.new(template) 74 75 x = nil 76 i = -1 77 found = false 78 @que[sz].each_with_index do |x, i| 79 if template.match(x) 80 found = true 81 break 82 end 83 end 84 return nil unless found 85 86 @que[sz].delete_at(i) 87 88 return x 89 end 90 91 def put_que(tuple) 92 sz = tuple.length 93 @que[sz] = [] unless @que[sz] 94 @que[sz].push tuple 95 end 96 private :get_que 97 private :put_que 98 99 def out(*tuples) 100 tuples.each do |tuple| 101 Thread.critical = true 102 put_que(tuple) 103 wakeup_waiting(tuple) 104 Thread.critical = false 105 end 106 end 107 alias put out 108 alias write out 109 110 def in(template, non_block=false) 111 begin 112 loop do 113 Thread.critical = true 114 tuple = get_que(template) 115 unless tuple 116 if non_block 117 raise ThreadError, "queue empty" 118 end 119 put_waiting(template, Thread.current) 120 Thread.stop 121 else 122 return tuple 123 end 124 end 125 ensure 126 Thread.critical = false 127 end 128 end 129 alias get in 130 alias take in 131 132 def rd(template, non_block=false) 133 tuple = self.in(template, non_block) 134 out(tuple) 135 tuple 136 end 137 alias read rd 138 139 def mv(dest, template, non_block=false) 140 tuple = self.in(template, non_block) 141 begin 142 dest.out(tuple) 143 rescue 144 self.out(tuple) 145 end 146 end 147 alias move mv 148end 149 150if __FILE__ == $0 151 ts = TupleSpace.new 152 clients = [] 153 servers = [] 154 155 def server(ts, id) 156 Thread.start { 157 loop do 158 req = ts.in(['req', nil, nil]) 159 ac = req[1] 160 num = req[2] 161 sleep id 162 ts.out([ac, id, num, num * num]) 163 end 164 } 165 end 166 167 def client(ts, n) 168 Thread.start { 169 ac = Object.new 170 tuples = (1..10).collect { |i| 171 ['req', ac, i * 10 + n] 172 } 173 ts.out(*tuples) 174 ts.out(tuples[0]) 175 puts "out: #{n}" 176 11.times do |i| 177 ans = ts.in([ac, nil, nil, nil]) 178 puts "client(#{n}) server(#{ans[1]}) #{ans[2]} #{ans[3]}" 179 end 180 } 181 end 182 183 def watcher(ts) 184 Thread.start { 185 loop do 186 begin 187 sleep 1 188 p ts.rd(['req', nil, nil], true) 189 rescue ThreadError 190 puts "'req' not found." 191 end 192 end 193 } 194 end 195 196 (0..3).each do |n| 197 servers.push(server(ts, n)) 198 end 199 200 (1..6).each do |n| 201 clients.push(client(ts, n)) 202 end 203 204 (1..3).each do 205 watcher(ts) 206 end 207 208 clients.each do |t| 209 t.join 210 end 211end 212 213 214 215