使用open和vwait在单独的进程中使用tar文件

时间:2016-11-18 16:22:20

标签: tcl tk event-loop

我有一个内置在Tcl / Tk中的GUI,它有一个按钮可以打开一个目录。 目录可能非常大,所以我不想在等待时锁定GUI。

为了实现这一点,我使用open命令管道和vwait,但是当tar运行时,GUI仍然没有响应。这是我的代码:

set ::compress_result 0
set pipe [open "|$tar_executable -cf $folder_to_tar.tar $folder_to_tar" r+]
fileevent $pipe readable "set ::compress_result [gets $pipe line]"

vwait ::compress_result
set return_value $::compress_result
unset ::compress_result
close $pipe

为什么这仍会阻止Tcl事件循环并锁定GUI?

2 个答案:

答案 0 :(得分:2)

你遇到的关键问题是这一行:

fileevent $pipe readable "set ::compress_result [gets $pipe line]"

从管道中立即读取行,因为[gets …]位于双引号字符串中。改为:

fileevent $pipe readable {set ::compress_result [gets $pipe line]}

使事情有效,因为它推迟了管道的读数,直到管道变得可读。但是,要做到这一点,它依赖于全局的pipe变量。实际上这样做更好:

fileevent $pipe readable [list apply {pipe {
    global compress_result
    set compress_result [gets $pipe line]
}} $pipe]

调试非常难看和笨拙,所以我们实际使用帮助程序:

proc pipedone {pipe} {
    global compress_result
    set compress_result [gets $pipe line]
}
fileevent $pipe readable [list pipedone $pipe]

这里使用list确实“将此引用为可运行的脚本以供日后使用”,以处理变量中可能出现的任何意外诡计。它知道如何正确引用事物,所以你不必这样做。

在Tcl 8.6中,你最好使用协程。

coroutine piperead apply {{tar folder} {
    # Open the pipe
    set pipe [open |[list $tar -cf $folder.tar $folder] "r"]
    # Wait until readable
    fileevent $pipe readable [info coroutine]
    yield
    # Read and close
    set return_result [gets $pipe line]
    close $pipe
    return $return_result
}} $tar_executable $folder_to_tar

答案 1 :(得分:0)

添加

fconfigure $pipe -blocking false

打开后,管道会有所帮助。