質問

スレーブインタープリターで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パッケージが必要です。

これが役立つことを願っています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top