【问题标题】:TCL gets command with kind of -nohang option?TCL 使用 -nohang 选项获取命令?
【发布时间】:2012-02-01 22:38:13
【问题描述】:

这是一个代码,它只是实现了一个带有命令提示符MyShell > 的交互式 TCL 会话。

puts -nonewline stdout "MyShell > "
flush stdout
catch { eval [gets stdin] } got
if { $got ne "" } {
    puts stderr $got
}

这段代码在终端提示MyShell >,等待回车键被按下;虽然它没有被击中,但代码什么也不做。这就是gets 命令的作用。

我需要的是gets 命令的替代方法,例如coolgetcoolget 命令不应该等待回车按钮,而是注册一些当它被击中时调用的槽,然后继续执行。所需的代码应如下所示:

proc evaluate { string } \
{
    catch { eval $string } got
    if { $got ne "" } {
        puts stderr $got
    }
}

puts -nonewline stdout "MyShell > "
flush stdout
coolgets stdin evaluate; # this command should not wait for the enter button
# here goes some code which is to be executed before the enter button is hit

这是我需要的:

proc prompt { } \
{
   puts -nonewline stdout "MyShell > "
   flush stdout
}


proc process { } \
{
   catch { uplevel #0 [gets stdin] } got
   if { $got ne "" } {
       puts stderr $got
       flush stderr
   }
   prompt
}

fileevent stdin readable process

prompt
while { true } { update; after 100 }

【问题讨论】:

    标签: tcl stdin interactive gets


    【解决方案1】:

    Tcl 将类似“nohang”的功能应用于整个通道,这是通过将通道配置为非阻塞来完成的。之后,任何read 将仅返回那里的数据,gets 将仅返回无需等待即可获得的完整行,puts(在可写通道上)将安排其输出发送到操作系统异步。 这取决于正在运行的事件循环。

    建议您将非阻塞通道与已注册的文件事件处理程序一起使用。您可以将其与非阻塞相结合来实现您的coolget 想法:

    proc coolget {channel callback} {
        fileevent $channel readable [list apply {{ch cb} {
            if {[gets $ch line] >= 0} {
                uplevel [lappend cb $line]
            } elseif {[eof $ch]} {
                # Remove handler at EOF: important!
                fileevent $ch readable {}
            }
        }} $channel $callback]
    }
    

    这样就可以正常工作了,除了你必须调用 vwaitupdate 来处理事件(除非你也使用了 Tk;Tk 是特殊的),因为 Tcl 不会处理背景中神奇的事物;神奇的后台处理带来的麻烦多于其价值……


    如果您在异步事件处理中纠缠不清,请考虑使用 Tcl 8.6 的 coroutines 来重构代码。特别是像Coronet 这样的代码可以提供很大帮助。然而,这非常依赖于 Tcl 8.6,因为早期的 Tcl 实现根本不支持协程;必须将低级实现从简单的 C 调用重写为延续以启用这些功能,而通过合理的努力,这不是可向后移植的。

    【讨论】:

      【解决方案2】:

      我认为您需要查看 fileevent、fconfigure 和 vwait 命令。使用这些,您可以执行以下操作:

      proc GetData {chan} {
          if {[gets $chan line] >= 0} {
             puts -nonewline "Read data: "
             puts $line
          }
      }
      
      fconfigure stdin -blocking 0 -buffering line -translation crlf
      fileevent stdin readable [list GetData stdin]
      
      vwait x
      

      此代码将 GetData 注册为标准输入的可读文件事件处理程序,因此只要有数据可供读取,就会调用它。

      【讨论】:

        猜你喜欢
        • 2012-10-27
        • 2021-01-19
        • 1970-01-01
        • 1970-01-01
        • 2014-09-28
        • 1970-01-01
        • 1970-01-01
        • 2011-06-24
        • 1970-01-01
        相关资源
        最近更新 更多