如何避免tcl中的主脚本因事件循环而被阻塞?

时间:2013-01-25 09:37:33

标签: tcl

我在我的tcl代码中使用了一个主脚本,我在其中打开一个udp端口来读取它上面的数据。我使用fileevent使用“vwait”命令进入事件循环。但我不希望由于这个原因阻止主脚本。总之,我希望主流脚本继续流动,等待udp数据事件应该在后台。如何实现这一目标。请帮我。我浪费了很多时间,但一切都在静脉中。任何帮助都会非常明显。

这是我的主要脚本:

#!/usr/bin/env tclsh8.5

proc create_udp_payload { command data } {
    set payload     ""
    append payload $command
    append payload  [ format %08x [ expr $data ] ]
    return $payload
}

proc send_udp_packet { payload } {
    puts -nonewline $soc::s [binary format H* $payload]
    puts "\nTransmitting the UDP payload $payload"
    return 0
}

set DEST_IP_ADDR        10.10.20.241
set DEST_UDP_PORT       5558
set soc::s              [udp_open]
puts "Listening on udp port : [fconfigure $soc::s -myport]"
udp_conf $soc::s $DEST_IP_ADDR $DEST_UDP_PORT
fconfigure $soc::s -buffering none -translation binary
fileevent $soc::s readable [list ::udp_listen]

for { set j 0 } { $j < 10 } { incr j} {
    puts "Sending read request to read register $j"
    set command "00"
    append command  [format %02x $j]
    send_udp_packet [create_udp_payload $command  0x0000]
    after 1000
    flush $soc::s
}

wait forever #to enter into the event loop

for { set j 2 } { $j < 12 } { incr j} {
    puts "Sending  write request to write register $j"
    set command "80"
    append command [format %02x $j]
    send_udp_packet [create_udp_payload $command [expr {0x0000 | $j }] ]
    after 2000
    flush $soc::s
}

实际上我想从硬件中逐个读取10个寄存器,我正在使用for循环,但我没有得到如何进入事件循环。因为它会阻止主脚本。此后,我想逐个编写10个相同硬件的寄存器。任何人都可以修改此代码以便相应地工作。提前感谢........

1 个答案:

答案 0 :(得分:0)

我认为使用after idle“技巧”可以轻松解决您的问题。我们的想法是设置“通道可读”事件处理程序,然后为“事件循环空闲”条件安排执行数据发送代码,然后进入事件循环:

像这样:

# 1. Create and configure the UDP endpoint:
set udp [udp_open ...]
...
# 2. Install "chan readable" callback handlers for that endpoint:
fileevent $udp readable ...
...
# 3. Schedule the one-off callback to send your data:
after idle [list post_data $udp]
# 4. Enter the event loop:
vwait ::done

一旦vwait被调用,事件循环机器就会看到是否有任何待处理事件(应该没有),并且一旦待处理事件队列耗尽或为空,所有处理程序都安装使用after idle被调用,您的数据将被发送出去。

请注意,此方法也适用于其他类似情况,例如,没有什么可以阻止您从事件循环调用的其他处理程序安装此类after idle处理程序。这使您永远不会离开事件循环(如GUI程序和网络服务器通常那样)。