[#4754] Now,I am starting ruby. — mamoru@... (Mamoru Matushita)

先日、初めて投稿したつもりだったのですが間違えて

14 messages 1997/10/02

[#4891] mixin - singleton method inheritance, const etc... — shugo@... (Shugo Maeda)

前田です。

13 messages 1997/10/10

[#5000] ruby 1.0-971015 released — matz@... (Yukihiro Matsumoto)

まつもと ゆきひろです

14 messages 1997/10/15

[#5056] RubyでOODB — hisanori@...

松尾です。

20 messages 1997/10/20
[#5057] Re: RubyでOODB — matz@... (Yukihiro Matsumoto) 1997/10/20

まつもと ゆきひろです

[#5065] Re: RubyでOODB — hisanori@... 1997/10/20

松尾です。

[#5066] Re: RubyでOODB — matz@... (Yukihiro Matsumoto) 1997/10/20

まつもと ゆきひろです

[ruby-list:5185] Re: listbox:curselection

From: Yuji Shigehiro <sigehiro@...>
Date: 1997-10-30 12:31:08 UTC
List: ruby-list #5185
しげひろです.

> Date: Tue, 28 Oct 97 10:11:48 +0900
> Subject: [ruby-list:5143] Re: listbox:curselection
> Message-Id: <199710280105.KAA28108@picachu.netlab.co.jp>

> ちなみに1.1b0ではtk.rbは重弘さんのtcltklibを使ったものになり
> ます.

うれしいです. 今の tcltklib の仕様のままだと, もっと嬉しいです (ruby 
のバージョンアップの時に毎回, 手で ext/ にコピーしなくて済むので...)

> スクリプトの互換性は保たれますが,thread safeではなく
> なります.

良く知らないのですが, thread safe とはどういうことなのでしょう???

 ----

tcltk ライブラリ (tcltk.rb) や tcltklib ライブラリと thread を共存させ
る方法について, いろいろやってみました.

ruby の thread は, ruby インタプリタが task switch するのですが,
TclTk.mainloop や TclTkLib.mainloop (すなわち Tk_MainLoop (n))を馬鹿正
直に呼ぶと, それらは ruby インタプリタに制御を戻さないので, それ以降 
task switch しなくなってしまいます.

以下のスクリプトは, tcl/tk により, print ボタン(標準出力に ---- を表示
する) と exit ボタンを生成しますが, 同時に, 別 thread (以下, 子 thread 
と呼びます)で標準出力に * をひたすら書こうとします.

が, 実行してみると, TclTk.mainloop に制御がわたってボタンが表示された
後は, 子 thread が止まります. print ボタンを何度かクリックすると,
print "*" するときに ruby インタプリタに制御が戻るので, 時々 task
switch しますが, これでは使えません.

しかし, [1] の部分をコメントイン(?)すると, ちゃんと task switch するよ
うになります. 何をしているかというと, tcl/tk のタイマを使って, 0.1 秒
毎に, (ruby インタプリタに実行される)コールバックの中から Thread.pass 
を呼んでいます.

ただし, (少なくとも FreeBSD では) 別 thread がバンバン実行されるので, 
クリックの反応が凄く悪くなります. そこで [2] の部分をコメントインする
と, まともに反応するようになります. (本文は, 更に下に続く.)

 ---- ここから ----
#! /usr/local/bin/ruby

require "tcltk"

# * を表示し続けるスレッド
th1 = Thread.new {
  while TRUE
    print "*"; $stdout.flush
#    Thread.pass # [2]
  end
}

# おまじない
ip = TclTkInterpreter.new()
root = ip.rootwidget()
$after, button, destroy, pack =
  ip.commands().indexes("after", "button", "destroy", "pack")

# ボタンの生成と表示
c1 = TclTkCallback.new(ip, proc{print "------\n"})
b1 = TclTkWidget.new(ip, root, button, "-text print -command", c1)
c2 = TclTkCallback.new(ip, proc{destroy.e(root)})
b2 = TclTkWidget.new(ip, root, button, "-text exit -command", c2)
pack.e(b1, b2)

#### [1] ここから
#$idlecallback = TclTkCallback.new(ip, proc{ idletask() })
#def idletask()
#  Thread.pass
#  $after.e("100", $idlecallback)
#end
#$after.e("100", $idlecallback)
#### [1] ここまで

TclTk.mainloop()
 ---- ここまで ----

で, いろいろやっているうちに, どうやら, 無理に TclTk.mainloop
(Tk_MainLoop (n)) を呼ぶ必要はなく, (tcl/tk の) update さえひたすら実
行して入れば良いのではないかと...

下のスクリプトは, [3] の部分で update し続けるのですが, ちゃんと動きま
す. (ただし, Tk_MainLoop と違って, root ウィジェットを destroy しても, 
イベントループから抜けてくれません.)

これだと, 常に ruby インタプリタが制御を握っているので, tcl/tk のタイ
マを使って面倒なことをする必要はありません.

もし, tcl/tk の C ライブラリが再入可能(?)ならば, これは thread safe と
いって良いのでしょうか?

 ---- ここから ----
#! /usr/local/bin/ruby

require "tcltk"

# * を表示し続けるスレッド
th1 = Thread.new {
  while TRUE
    print "*"; $stdout.flush
    Thread.pass
  end
}

# おまじない
ip = TclTkInterpreter.new()
root = ip.rootwidget()
button, pack, update =
  ip.commands().indexes("button", "pack", "update")

# ボタンの生成と表示
c1 = TclTkCallback.new(ip, proc{print "------\n"})
b1 = TclTkWidget.new(ip, root, button, "-text print -command", c1)
c2 = TclTkCallback.new(ip, proc{exit})
b2 = TclTkWidget.new(ip, root, button, "-text exit -command", c2)
pack.e(b1, b2)

#### [3] ここから
while TRUE
  update.e()
  Thread.pass
end
#### [3] ここまで
 ---- ここまで ----

(次回の tcltk.rb の公開時には, このあたりの仕組みをなんとかしなければ...)

----
重弘裕二
阪大情報処理教育センター (sigehiro@rd.ecip.osaka-u.ac.jp)
阪大工情報システム白川研 (sigehiro@ise.eng.osaka-u.ac.jp)

In This Thread