如何使用Tcl(interp)bgerror

时间:2009-09-14 12:17:47

标签: tcl interpreter slave

我正在尝试run tclhttpd in a slave interpreter但稍加修改以便在tclkit中运行。下面的代码“运行”(我可以点击http://localhost:8015)但是从未到达底部的puts行,因为“服务器没有返回,它进入[vwait forever]”。但是,当我尝试“后0技巧”时,例如将“0之后”添加到“$ httpd eval $ cmd”行,服务器根本不运行,所以我假设“错误必须由bgerror处理”

但是我找不到如何使用bgerror的好例子,而且我的研究表明现在的惯例是使用“interp bgerror”。请参阅http://www2.tcl.tk/_/gsearch?S=bgerror返回的前几个示例;第一个链接包含“填写有用的技巧和使用bgerror的示例”的措辞,但是没有样本我可以看出如何应用,第二个链接得出结论“我对如何使用这个例子感兴趣”。

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"

3 个答案:

答案 0 :(得分:2)

根据OP的评论完全编辑......

后0技巧是以下一行:

after 0 $httpd eval $cmd

这样做是告诉interp将有问题的命令($ http eval $ cmd)添加到事件队列中,这意味着它将在事件循环启动后运行(或者如果它已经启动则返回)。您可以在该页面的以下评论中看到对事件循环的依赖(Jacob Levy):

  

我应该注意,这取决于活动的事件循环。

我的猜测是你正在运行一个普通的Tclsh,这意味着你永远不会进入事件循环(Wish shell在脚本结束时进入事件循环,而Tcl shell则没有)。进入事件循环的标准方法是在到达Tcl代码结束时运行以下命令:

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

话虽如此,在退出事件循环之后,你在vwait之后拥有的任何东西都不会运行。如果您希望httpd与代码并行运行,则需要:

  • 使用多个线程,或写下你真正不那么难的......
  • 基于事件的代码...这要求您理解甚至基于编程的程序,以防止代码片段缺乏执行时间。

希望有所帮助。

答案 1 :(得分:1)

如果我已经正确理解了您的想法,那么您的代码应该类似于:

set httpd_id [thread::create -preserved]
thread::send $http_id "source [file join $starkit::topdir bin/httpd.tcl]"

通过这种方式,您可以在线程中运行TclHttpd,而无需担心vwait问题

如果您还希望在httpd执行期间被告知任何错误,TclHttp会将所有错误发送到日志文件。您可以配置日志的路径:

Log_SetFile "/logs/httpd_log"

您需要拥有httpd :: log包。

我希望这会有所帮助。

答案 2 :(得分:1)

我不太明白你问的问题。听起来你的目标是在一个解释器中启动一个http服务器,但不知何故与主解释器交互。是对的吗?如果是这样,那与bgerror有什么关系?

您是否知道即使您在一个单独的解释器中运行服务器,它在一个单独的线程中运行?也就是说,当解释器被vwait阻塞时,你不能(*)与主解释器交互。

(*)您可以,如果您的互动采用Tk小部件的形式,也可以利用事件循环

至于如何使用bgerror,它有两种方法可行。默认机制调用函数'bgerror',您可以将其定义为执行任何操作。它需要一个字符串(错误消息的文本)并对其执行某些操作。某些内容可以是将错误打印到stdout,在对话框中显示,将其写入文件等

作为示例,请考虑此交互式会话:

% 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中出现的,虽然它有一个bug,直到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

这有助于回答您的问题吗?