It will wake up when the channel is closed. But the
window cannot be moved, even though there
are a liberal amount of update calls
being made during each call to wait. Also, the
output text does not show up until the
channel is closed (when the parent exits). The
variable n tells me that it did actually loop a
number of times.
This is a 8.5.2 windows tcklit.exe on win2000.
I am invoking it as follows, from this 2 line program.
set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
puts $::console "hello from the main" ; flush $::console
Here's the tail.tcl program,
# --------------------------------------------------
proc wait {time} {
for {set n 0} {$n < 5} {incr n} {
after [expr ( int($time / 5) )]
update
}
}
console show
console eval {wm geom . 120x7+50+600}
update
wm wi .
fconfigure stdin -blocking 0
puts "starting....";update
set n 0
while { true } {
incr n
set out [gets stdin data]
if { [eof stdin] } {
puts "eof seen" ; update
break
}
if { $out < 0 } {
wait 250
continue
}
puts " $n) $data" ; update
}
puts "done..." ;update
wait 10000
exit
Are you aware that "after <number>" sleeps for that number of
milliseconds without processing events, during which your program will
freeze? In other words, your app freezes because you are telling it to.
Also, since you are running an event loop there's no reason to have your
own infinite loop -- the event loop is, after all, an infinite loop.
Another good rule of thumb is, never call update. Unless you fully
understand the implications it's best to avoid the tempation.
If you want a procedure to be called every N milliseconds, simply create
a job and reschedule it at the appropriate interval, letting the event
loop do the work:
proc readData {delay} {
<do whatever processing you want>
# reschedule this procedure after $delay ms unless
# some terminal condition is met
if {! <some condition>} {
after $delay [list readData $delay]
}
}
# run the first iteration
readData 250
No doubt others will advocate using [info level] rather than hard-coding
what gets executed. It's a perfectly fine solution, but I think this
more clearly illustrates what is happening.
Finally, search for "tail" on the tcler's wiki. There are many examples.
I'm placing you in my quote file. Well said :)
Well, something else is going on here then. Here's the new version,
same
problem, no update calls, written as suggested.
(BTW, my wait proc in the original breaks up the call to wait
into 5 smaller waits, each of 50 ms, with an update call - this
should have worked as far as I can tell)
In this new case, as soon as I launch this, I get 2 windows, one is
simply
the empty toplevel that the the main program creates when called by
tclkit
and no widgets are created. The second is the console window created
by
the exec'd tail.tcl program.
AFter the 2 windows appear, if I click in the console window first, it
works, but if I click on the main's toplevel window, the console
window
again becomes busy and hangs. If I put another puts inside the proc,
it
will spit out a line each time the timer goes off, but the console
window
is still frozen.
Alternatively, if I create a simple exit button, like so, the
behavior is slightly different.
Now, if I just launch this, and don't move the mouse over the console
windows, it will spit out the "out = # now waiting", and # is
increasing each time. As soon as the mouse is simply moved over
the console window (no button clicking), then the window freezes,
the cursor becomes the busy (sand timer) cursor, and the output stops.
The console window is still unselected, but is now frozen. Clicking on
the exit button in the main program causes the console window to say
it say the eof and then it exits in 1 second later.
# -------------------------------------------------------------
pack [button .b -text exit -command exit]
set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
puts $::console "hello from the main"
flush $::console
# ---------------------------------------------
console show
console eval {wm geom . 120x7+50+600}
wm wi .
fconfigure stdin -blocking 0
puts "starting...."
set num 0
proc readData {delay} {
global num
incr num
set out [gets stdin data]
if { [eof stdin] } {
puts "$num eof seen"
after 2000 exit
return
}
if { $out < 0 } {
puts "out = $num now waiting"
after $delay {readData 250}
return
}
puts "$num) $data"
after $delay {readData 250}
}
readData 250
If the proc needs to definitely re-run after the delay, it might be
preferable to reschedule first, then do the work. This way, an error
while doing the work does not cause the schedule to stop. Of course
if the repeat-interval is short and the error is repeating, you get
tons of error windows in wish :-).
set ::after_id {}
proc readData {delay} {
after cancel $::after_id
set ::after_id [after $delay [list readData $delay]]
<do whatever processing you want>
}
readData ...
YMMV.
R'
I don't see what difference this would make to
the problem I am seeing. My goal is not to implement
a "tail" program that reacts instantly, I just need
to be able to write to this stream from one process
and see the output in the other. Actually, I was looking
for a solution to the problem of puts from a thread not
working on windows, like it does on *nix systems.
This tail program is really just the aspect of the
unix tail that would let you write to a file from
one process and display the results as they were
output in another windows using tail -f. In fact, I
began this with files, but then hit on the pipeline
idea.
What I can't figure is how the existence of the
exit button in one process affects the other
process at all. That is strange and seems to
indicate some sort of focus problem - maybe
a bug. I'm curious if anyone else can even
reproduce this behavior with the above
code.
Note, the above describes 2 programs, with the
4 lines between the two comment #---- lines
being the first, and the second section is
the "tail" program.
None. Sorry, I should probably have adjusted the 'Subject' line,
since my reply was targeted at a completely different aspect in Bryans
reply (Message-ID: <yV9gk.30548$co7....@nlpi066.nbdc.sbc.com>).
Did you see that reply by Bryan Oakley? It points out some problems
with your code which seem to be crucial to the answer to your original
question.
R'
Yes, I saw his reply, and I tried to implement the code just as he
had suggested, which I posted. Unfortunately, his suggestion, while
useful as technique for avoiding update calls, didn't resolve the
issue I have. Since I can't see what the problem is, I can't use
this technique to provide a debug output console for threads. I'm
at the point where I was going to write something using a text widget
in case the problem is in the console code. But I'm afraid
I'll just come up against the same bug (I now believe this
is a bug in tcl/tk).
Thanks
I have to admit that I do not know much about tclcon on windows, and
the differences of TclCon (or Tkcon?) to plain TCL/Tk, so take the
following with a grain of salt.
The code you posted in
Message-ID: <31c36f47-9447-47cd...@v26g2000prm.googlegroups.com>
starts with
set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
That sounds strange to my TCL-ears. Why use the '&' sign in there if
opening a pipe? Usually I would have expected
# redirect stderr to see debugging messages
set ::console [open "|tclkit-win32.upx.exe tail.tcl 2>@stderr" w]
And in tail.tcl just set up a fileevent for stdin, and let the
callback handle the input:
proc handle_stdin {} {
set count [gets stdin data]
if { [eof stdin] } {
puts stderr "eof seen on stdin, exiting"
close stdin
exit 0
}
if { $count > 0 } {
puts stderr "READ from stdin {$data}"
}
}
fconfigure stdin -blocking 0
fileevent stdin readable handle_stdin
# The following vwait is only necessary in a tclsh which has no
# event loop by itself (eg. wish already has an event loop running)
vwait forever
HTH
R'
> The code you posted in
> Message-ID: <31c36f47-9447-47cd-b6b2-294f7581d...@v26g2000prm.googlegroups.com>
> starts with
> set ::console [open "|tclkit-win32.upx.exe {tail.tcl} &" w]
>
> That sounds strange to my TCL-ears. Why use the '&' sign in there if
> opening a pipe? Usually I would have expected
>
> # redirect stderr to see debugging messages
> set ::console [open "|tclkit-win32.upx.exe tail.tcl 2>@stderr" w]
>
I used the & because I read that when using the pipe symbol | in
the open statement, that what follows is the same as when using
exec. And I use & with exec so it does not wait until the
exec'd process exits.
Anyway, I tried your suggestion, and I get an error. It says
channel "console2" wasn't opened for writing, so I'm not sure
what tcl thinks I'm doing nor do I understand what's going on
here either. I have no console2 anywhere, so I'm guessing it's
some syntax issue with the ::console and the 2 in the redirection
that is getting messed up.
Next, I tried your suggestion, still using my original
open statement, with the following code, with no change
in behavior. (But the code keeps getting smaller :)
package require Tk ;# just a guess
console show
console eval {wm geom . 120x7+50+600}
wm wi .
fconfigure stdin -blocking 0
puts "starting...."
set num 0
proc handle_stdin {} {
global num
incr num
set count [gets stdin data]
if { [eof stdin] } {
puts "eof seen on stdin, exiting"
fileevent stdin readable {} ;# remove handler
close stdin
after 16000 {exit 0} ;# delay exit so this is visible
}
if { $count > 0 } {
puts "$num) $data"
}
}
fileevent stdin readable handle_stdin
vwait forever
Ok, this sounds like a minor flaw in the 'open' documentation. With
'exec' you need the "&", otherwise your app is blocked until the
exec'd program finishes. With 'open', you don't need the "&" because
your program is not blocked here. The side-effect of using an "&" is
to redirect stdout and stderr of the application (which actually might
be what you want). I'm not sure whether this side-effect is
intentional in the case of 'open', though.
set ::console [open "|tclkit-win32.upx.exe tail.tcl &" w]
would then be the same as
set ::console [open "|tclkit-win32.upx.exe tail.tcl >@stdout 2>@stderr" w]
| Anyway, I tried your suggestion, and I get an error. It says
| channel "console2" wasn't opened for writing, so I'm not sure
| what tcl thinks I'm doing nor do I understand what's going on
| here either.
That's because omitting the "&" now closed the stdout of the
application and the 'puts' in there failed. So either keep the "&" or
use explicit redirection as shown above.
| [tail.tcl]
| package require Tk ;# just a guess
Good for starting the event loop, you don't need the 'vwait' then.
| console show
| console eval {wm geom . 120x7+50+600}
Not sure about these... Is this the window where the output is shown?
| wm wi .
| fconfigure stdin -blocking 0
| puts "starting...."
This 'puts' may fail if the program was started with a write-only pipe
(see above).
| set num 0
| proc handle_stdin {} {
| global num
| incr num
| set count [gets stdin data]
| if { [eof stdin] } {
| puts "eof seen on stdin, exiting"
| fileevent stdin readable {} ;# remove handler
That's not necessary, 'close' will take care of that.
| close stdin
| after 16000 {exit 0} ;# delay exit so this is visible
| }
| if { $count > 0 } {
| puts "$num) $data"
| }
| }
| fileevent stdin readable handle_stdin
| vwait forever
'vwait' should not be necessary if you 'required' Tk earlier.
If this still does not work, I'm out of ideas. Must be some
interaction with the console, since it works here with tclsh and/or
wish.
HTH
R'