1

スレーブ インタープリターで tclhttpd を実行しようとしていますが、tclkit 内で実行するように少し変更しています。以下のコードは「実行」されます ( http://localhost:8015をヒットできます) が、「サーバーが返されず、[vwait forever] に入る」ため、下部の puts 行には到達しません。しかし、「$httpd eval $cmd」の行に「after 0」を追加するなど、「after 0 トリック」を試すと、サーバーはまったく実行されないため、「エラーは bgerror で処理する必要がある」と推測します。

ただし、bgerror の使用方法の良い例を見つけることができません。さらに、私の調査によると、現在は "interp bgerror" を使用するのが慣習になっています。http://www2.tcl.tk/_/gsearch?S=bgerrorによって返される最初の 2 つの例を参照してください。最初のリンクには「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"
4

3 に答える 3

2

OPのコメントをもとに完全編集…

after 0 トリックは次の行です。

after 0 $httpd eval $cmd

これが行うことは、問題のコマンド ($http eval $cmd) をイベント キューに追加するように interp に指示することです。つまり、イベント ループが開始されると実行されます (または、既に開始されている場合は戻ります)。そのページの次のコメントで、イベント ループへの依存を確認できます (Jacob Levy による)。

これは、アクティブなイベント ループに依存することに注意してください。

私の推測では、単純な Tclsh を実行しているため、イベント ループに入ることはありません (Wish シェルはスクリプトの最後でイベント ループに入りますが、Tcl シェルは入りません)。イベント ループに入る標準的な方法は、Tcl コードの最後に到達したら、次のコマンドを実行することです。

# Enter the event loop and stay in it until someone 
# sets the "forever" variable to something
vwait forever

そうは言っても、vwait の後にあるものは、イベント ループが終了するまで実行されません。コードと並行して httpd を実行するには、次のいずれかを行う必要があります。

  • 複数のスレッドを使用するか、あなたの...を書くのはそれほど難しいことではありません
  • コードをイベントベースにする必要があります...これには、コードの断片が実行時間の不足にならないように、ベースプログラミングでさえ十分に理解する必要があります。

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

于 2009-09-14T16:44:15.267 に答える
1

あなたが何をしたいのかを正しく理解していれば、コードは次のようになります。

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 パッケージが必要です。

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

于 2009-09-23T21:41:38.950 に答える
1

私はあなたが尋ねている質問をよく理解していません。あなたの目標は、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

これはあなたの質問に答えるのに役立ちますか?

于 2009-09-24T18:37:04.057 に答える