Tclの(interp)bgerrorの使用方法
-
07-07-2019 - |
質問
スレーブインタープリターでtclhttpdを実行しようとしていますが、内部で実行するようにわずかに変更していますtclkit。以下のコードは「実行」します。 ( http:// localhost:8015 にアクセスできます)でも、サーバーが"戻りません。[vwait forever]"に入ります。しかし、「the after 0 trick」を試してみると、先頭に" 0の後" " $ httpd eval $ cmd"の行では、サーバーはまったく実行されないため、「エラーはbgerrorで処理する必要があります」
ただし、bgerrorの使用方法の良い例を見つけることはできません。さらに、私の調査では、今では「interp bgerror」を使用することが慣例となっていることを示しています。 http://www2.tcl.tk/_によって返される最初の例を参照してください。 / gsearch?S = bgerror ;最初のリンクには、「bgerrorを使用するための有用なトリックと例を記入する」という言葉が含まれています。ただし、適用方法を識別できるサンプルはありません。2番目のリンクでは、「これがどのように使用されるかを例に興味があります」と結論付けています。
package require starkit
starkit::startup
set httpd_args [list]
set httpd [interp create]
$httpd eval "set argc [llength $httpd_args]"
set cmdargv "set argv [list $httpd_args ]"
$httpd eval "set topdir $starkit::topdir"
$httpd eval $cmdargv
set cmd [list source [file join $starkit::topdir bin/httpd.tcl]]
$httpd eval $cmd
puts "if seeing this controlled has returned"
解決
私はあなたが尋ねている質問をよく理解していません。あなたの目標は、1つのインタープリターでhttpサーバーを起動することですが、どういうわけかメインのインタープリターとやり取りすることです。そうですか?もしそうなら、それはbgerrorと何の関係があるのですか?
サーバーを別のインタープリターで実行していても、別のスレッドで実行されていないことを認識していますか?つまり、いずれかのインタープリターがvwaitによってブロックされている間は、メインインタープリターと対話(*)できません。
(*)インタラクションがイベントループも利用するTkウィジェットの形式をとる場合、可能です
bgerrorの使用方法については、いくつかの方法があります。デフォルトのメカニズムは、関数「bgerror」を呼び出します。好きなことをするように定義できます。単一の文字列(エラーメッセージのテキスト)を受け取り、それに対して何かを行います。その何かは、エラーを標準出力に出力したり、ダイアログに表示したり、ファイルに書き込んだりすることです。
例として、次の対話型セッションを検討してください。
% proc bgerror {s} {puts "hey! I caught an error: $s"}
% # after 30 seconds, throw an error
% after 30000 {error "this is an error"}
after#0
% # after 40 seconds, terminate the event loop
% after 40000 {set ::done 1}
after#1
% # start the event loop
% vwait ::done
hey! I caught an error: this is an error
% # this prompt appears after 40 seconds or so
「interp bgerror」のドキュメントで説明されているように、独自のエラーハンドラを登録することもできます。これはtcl 8.5で発生しましたが、バグ 8.5.3まで修正されませんでした。
例:
% set foo [interp create]
interp0
% $foo eval {proc myErrorHandler {args} {puts "myErrorHandler: $args"}}
% $foo bgerror myErrorHandler
myErrorHandler
% # after 30 seconds, throw an error
% $foo eval {after 30000 {error "this is an error"}}
after#0
% # after 40 seconds, terminate the loop
% $foo eval {after 40000 {set ::done 1}}
after#1
% $foo eval {vwait ::done}
myErrorHandler: {this is an error} {-code 1 -level 0 -errorcode NONE -errorinfo {this is an error
while executing
"error "this is an error""
("after" script)} -errorline 1}
% # this prompt appears after 40 seconds or so
これはあなたの質問に答えるのに役立ちますか?
他のヒント
OPのコメントに基づいて完全に編集...
after 0のトリックは次の行です:
after 0 $httpd eval $cmd
これは、interpに問題のコマンド($ http eval $ cmd)をイベントキューに追加するように指示します。つまり、イベントループが開始されると(または既に開始されている場合は戻ります)実行されます。イベントループへの依存は、そのページからの次のコメントで見ることができます(ジェイコブ・レヴィによる):
これは、アクティブなイベントループに依存することに注意してください。
単純なTclshを実行していると思います。つまり、イベントループに入らないことを意味します(Wishシェルはスクリプトの最後にイベントループに入りますが、Tclシェルは入らない)。イベントループに入る標準的な方法は、Tclコードの最後に到達したら次のコマンドを実行することです。
# Enter the event loop and stay in it until someone
# sets the "forever" variable to something
vwait forever
つまり、vwaitの後は、イベントループが終了するまで実行されません。 httpdをコードと並行して実行するには、次のいずれかを実行する必要があります。
- 複数のスレッドを使用するか、...を記述します。これはそれほど難しくありません
- イベントベースのコード...これは、コードの断片が実行時間を奪うのを防ぐのに十分なベースのプログラミングを十分に理解する必要があります。
役立つこと。
あなたが何をしたいのかを正しく理解できた場合、コードは次のようになります。
set httpd_id [thread::create -preserved]
thread::send $http_id "source [file join $starkit::topdir bin/httpd.tcl]"
このようにして、vwaitの問題を心配することなく、TclHttpdをスレッドで実行できます
httpdの実行中にエラーについても通知する場合、TclHttpはすべてのエラーをログファイルに送信します。ログ実行のパスを設定できます:
Log_SetFile "/logs/httpd_log"
httpd :: logパッケージが必要です。
これが役立つことを願っています。