Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Make your own synchronization mechanism.

Make your own synchronization mechanism.

RubyKaigi2014

seki at druby.org

September 20, 2014
Tweet

More Decks by seki at druby.org

Other Decks in Programming

Transcript

  1. slide sponsors !LPV ؙٔ،؝٦سծ荈歋ח⢪ִ׷اؿزؐؑ،׾Ꟛ涪ׅ׷➂׾⹫꧊ չؙٔ،؝٦سػحث䱰欽պד嗚稊 !NBNF ְַ׃׋خ؎٦زח鸨ְ׋ְז׵չהגַպח꧊ת׶ת׃׳ ֲ 㹋遤㨻㆞ꞿ⤘״׶ 

    !KVOF ꟼׁ׿ךز٦ؙכծ䞸׸ׇׁせ鎉׌ה䙼׏ג耮ֻהׁ׵ח嚂׃׭ ׷״ֲחז׶תׅ !UTVCPJ3VCZ,BJHJח遤ֽזְךדծ✮皾׾ֿ׍׵ח䫎♴׃תׅկ״ְ涪邌 ׾կ !1613-׮⿫⸇ׅ׷הגַדכծׁ׵ז׷⿫⸇罏׾ֶת׍׃גְתׅկ !IJSBZBTVؿؑ؎ز׍ׯ׿ַ׻ְְ״IUUQXXXGBUFNPF !PHJKVO֮הד剅ֻ !ZBODZB!IJTBTIJN!WFTUJHF@!OPQMBOT!USBDL
  2. ph.2 ࣗ෼ͰٳΉ࡞ઓ def initialize(size=0) @size = size if size ==

    0 @writing = SizedQueue.new(1) else @writing = SizedQueue.new(size) end end def read return @writing.pop if @size > 0 value, writer = @writing.pop return value ensure writer.wakeup if @size == 0 end def write(value) return @writing.push(value) if @size > 0 @writing.push([value, Thread.current]) sleep end 5ISFBE׾床׃ג 饯ֿ׃ג׮׵ֲ 5ISFBE׾床׃ג 饯ֿ׃ג׮׵ֲ
  3. wakeupͷ͋ͱʹsleep... def initialize(size=0) @size = size if size == 0

    @writing = SizedQueue.new(1) else @writing = SizedQueue.new(size) end end def read return @writing.pop if @size > 0 value, writer = @writing.pop return value ensure writer.wakeup if @size == 0 end def write(value) return @writing.push(value) if @size > 0 @writing.push([value, Thread.current]) sleep end ر٦ة ꟦麩ְ
  4. όοϑΝΛ਺͑Δ܎ def initialize(size) @reading = Queue.new @writing = Queue.new size.times

    { @reading.push(true) } end def read @reading.push(true) @writing.pop end def write(value) @reading.pop @writing.push(value) end ر٦ة
  5. QueueͰηϚϑΥ def initialize(size) @reading = Queue.new @writing = Queue.new size.times

    { @reading.push(true) } end def read @reading.push(true) @writing.pop end def write(value) @reading.pop @writing.push(value) end ず劍欽 ず劍欽 إوؿؓ
  6. όοϑΝ෼up͠ͱ͘ def initialize(size) @reading = Queue.new @writing = Queue.new size.times

    { @reading.push(true) } end def read @reading.push(true) @writing.pop end def write(value) @reading.pop @writing.push(value) end غحؿ؋ⴓ
  7. ࢖͍ํ͔Βઃܭ͢Δ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read
  8. openͰੜ੒ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read إوؿؓ PQFO )BOEMF
  9. write/read chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read XSJUF SFBE
  10. nඵޙʹͳʹ͔ૹΔνϟωϧ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read TFD
  11. readableΛฦ͢ chan1 = ChannelSpace.open(1) chan1.write('hello') p chan1.read chan2 = ChannelSpace.open(0)

    timeout = ChannelSpace.after(10) readable = ChannelSpace.select([chan1, chan2, timeout]) p readable.read BSSBZ ׉ך䖓 SFBE
  12. Ͱ͖ͨ # -*- coding: utf-8 -*- require 'rinda/tuplespace' class ChannelSpace

    include DRbUndumped class ChannelError < RuntimeError def initialize(str, handle) @channel = handle super(str) end attr_reader :channel end class Readable def ===(it) it.readable? end end class Any def initialize(ary) @ary = ary end def ===(it) @ary.include?(it) end end class Channel def initialize(ts, size, handle) @ts = ts @handle = handle @reader = [] @writer = [] @buf = [] @size = size @closed = false end def readable? _readable? || @closed end def _readable? @buf.size + @writer.size > 0 end def close @closed = true while writer = @writer.shift @ts.write([:write, @handle, writer[1], self]) end while reader = @reader.shift @ts.write([:read, @handle, reader, self]) end end def writer_shift return if @writer.empty? value, key = @writer.shift @buf << value @ts.write([:write, @handle, key, value]) end def buf_push(value) @writer << [value, Thread.current] if @buf.size < @size writer_shift end end def buf_shift writer_shift @buf.shift end def req_read if _readable? @ts.write([:read, @handle, Thread.current, buf_shift]) else raise ChannelError.new('closed channel.', @handle) if @closed @reader << Thread.current end end def req_write(value) raise ChannelError.new('closed channel.', @handle) if @closed buf_push(value) return if @reader.empty? @ts.write([:read, @handle, @reader.shift, buf_shift]) end end class Handle include DRbUndumped def initialize(cs) @cs = cs end def write(value) @cs.write(self, value) end def read @cs.read(self) end def close @cs.close(self) end end def initialize @ts = Rinda::TupleSpace.new @readable = Readable.new end def open(size=0) handle = Handle.new(self) @ts.write([handle, Channel.new(@ts, size, handle)]) handle end def close(handle) begin _, chan = @ts.take([handle, nil]) chan.close ensure @ts.write([handle, chan]) end end def write(handle, value) begin _, chan = @ts.take([handle, nil]) chan.req_write(value) ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:write, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def read(handle) begin _, chan = @ts.take([handle, nil]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def select(set) handle, _ = @ts.read([Any.new(set), @readable]) handle end def select_and_read(set) begin handle, chan = @ts.take([Any.new(set), @readable]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan return handle, value end def after(sec, value=nil) chan = open Thread.new {sleep sec; chan.write(value)} chan end @cs = self.new def self.open(size=0) @cs.open(size) end def self.after(sec, value=nil) @cs.after(sec, value) end def self.select(set) @cs.select(set) end def self.select_and_read(set) @cs.select_and_read(set) end end
  13. ର৅ʹ஫໨ͨ͠ഉଞ੍ޚ def write(handle, value) begin _, chan = @ts.take([handle, nil])

    chan.req_write(value) ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:write, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def read(handle) begin _, chan = @ts.take([handle, nil]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end UBLF XSJUF UBLF XSJUF UBLF XSJUF UBLF XSJUF 㥨ֹז 乼⡲
  14. Actor෩௨৴ def write(handle, value) begin _, chan = @ts.take([handle, nil])

    chan.req_write(value) ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:write, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end def read(handle) begin _, chan = @ts.take([handle, nil]) chan.req_read ensure @ts.write([handle, chan]) end _, _, _, value = @ts.take([:read, handle, Thread.current, nil]) raise ChannelError.new('closed channel.', handle) if value == chan value end SFRVFTU SFR SFT SFT GSPN IBOEMF WBMVF LJOE
  15. selectͷ࣮૷ def select(set) handle, _ = @ts.read([Any.new(set), @readable]) handle end

    ... class Readable def ===(it) it.readable? end end class Any def initialize(ary) @ary = ary end def ===(it) @ary.include?(it) end end  DIBOOFM IBOEMF DIBOOFM IBOEMF DIBOOFM IBOEMF 
  16. selectͷ࣮૷ def select(set) handle, _ = @ts.read([Any.new(set), @readable]) handle end

    ... class Readable def ===(it) it.readable? end end class Any def initialize(ary) @ary = ary end def ===(it) @ary.include?(it) end end  DIBOOFM IBOEMF DIBOOFM IBOEMF DIBOOFM IBOEMF ػة٦ٝ UTSFBE