From: Masatoshi SEKI Date: 2000-07-11T01:30:09+09:00 Subject: [ruby-list:23787] Re: context switch during finalizer(Re: Re: Flyweight) 咳といいます。 > なるほど。多くのライブラリはあんまりスレッドのことを考慮せず > に書いてあります、かもしれません。スレッド標準装備をうたって > るんだから、もうちょっとスレッド対応が簡単な方がよいかも。 > Javaのsyncronized構文とか導入した方が良いのかなあ。 どうなんでしょう。 最近 mutex_m.rb を改造して遊んでました。 (1) synchronize 中、そのスレッドは synchronize 可能 な synchronize (2) synchronize 中でないと例外を発生させる in_synchronize (3) attr_reader/writer/accessor のようなもので 同期する synchronize_reader/writer/accessor や lockしてないと例外を発生させる lock_reader/writer/accessor (4) メソッドを alias して同じ名前で synchronize do ... end を def する synchronized などを追加してみました。 どれがアプリを書くときに有効か、いろいろ試してるところです。 # (3),(4)の実装がちょっと怪しいけどそれなりに動いてます。 mutex_m の様にオブジェクト自身に lock をかける場合、 (1) があるとややうれしいかも。 深く考えずにメソッドの中をsynchronize do .. end できるので。 # 使用例 class Foo include MutexO_m def initialize super @foo = nil @bar = nil @count = 0 end synchronize_accessor(:foo) # synchronizeする accessor lock_accessor("bar") # lockしてないと例外が起きる accessor def commit in_synchronize # lockしてないと例外が起きるよ! p [@foo, @bar] end def sleep_and_set # 強引なサンプル sleep 0.5 @foo = @foo + @foo sleep 0.5 @bar = @bar + @foo [@foo, @bar] end synchronized :sleep_and_set # synchronizeで同期されます。 end f = Foo.new f.foo = 1 p f f.synchronize do f.foo = 3 # 二重に synchronizeするけど平気 f.bar = 2 # synchronize中なので例外起きない f.commit end p f begin f.bar = 4 # lockしてないので例外 rescue ThreadError p $! end p f Thread.new do p f.sleep_and_set # synchronizedしてあるので安全 end sleep 0.2 f.foo = 5 # sleep_and_set が完了してから変更 sleep 2 p f -- mutexo_m.rb module MutexO_m def MutexO_m.append_features(cl) super unless cl.instance_of?(Module) cl.module_eval %q{ alias locked? mu_locked? alias lock mu_lock alias unlock mu_unlock alias try_lock mu_try_lock alias synchronize mu_synchronize alias in_synchronize mu_in_synchronize } end def cl.synchronize_reader(attr) begin attr = attr.id2name rescue NameError end module_eval("def #{attr}; synchronize do return @#{attr} end; end") end def cl.synchronize_writer(attr) begin attr = attr.id2name rescue NameError end module_eval("def #{attr}=(p); synchronize do @#{attr}=p end; end") end def cl.synchronize_accessor(attr) synchronize_reader(attr) synchronize_writer(attr) end def cl.lock_reader(attr) begin attr = attr.id2name rescue NameError end module_eval("def #{attr}; mu_in_synchronize; return @#{attr}; end") end def cl.lock_writer(attr) begin attr = attr.id2name rescue NameError end module_eval("def #{attr}=(p); mu_in_synchronize; @#{attr}=p ; end") end def cl.lock_accessor(attr) lock_reader(attr) lock_writer(attr) end def cl.synchronized(method) begin method = method.id2name rescue NameError end org = "_mu_#{method}" module_eval("alias #{org} #{method}") module_eval("def #{method}; synchronize do #{org} end; end") private(org) end return self end def MutexO_m.extend_object(obj) super obj.mu_extended end def mu_extended unless (defined? locked? and defined? lock and defined? unlock and defined? try_lock and defined? synchronize) eval "class << self alias locked? mu_locked? alias lock mu_lock alias unlock mu_unlock alias try_lock mu_try_lock alias synchronize mu_synchronize alias in_synchronize mu_in_synchronize end" end initialize end # locking def mu_synchronize return yield if @mu_locked == Thread.current begin mu_lock yield ensure mu_unlock end end def mu_locked? @mu_locked ? true : false end def mu_try_lock result = false Thread.critical = true unless @mu_locked @mu_locked = Thread.current result = true end Thread.critical = false result end def mu_lock while (Thread.critical = true; @mu_locked) @mu_waiting.push Thread.current Thread.stop end @mu_locked = Thread.current mu_on_lock Thread.critical = false self end def mu_unlock return unless @mu_locked Thread.critical = true wait = @mu_waiting @mu_waiting = [] @mu_locked = nil mu_on_unlock Thread.critical = false for w in wait w.run end self end def mu_in_synchronize raise(ThreadError, 'no lock') unless @mu_locked == Thread.current end private # fook def mu_on_lock end def mu_on_unlock end def initialize(*args) ret = super @mu_waiting = [] @mu_locked = nil return ret end end