Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to interrupt a task which is running in a thread?

160 views
Skip to first unread message

Andy

unread,
Sep 13, 2012, 6:14:43 AM9/13/12
to
How to interrupt a task which is running in a thread? Just like Control+C is pressed.
I don't mean kill the thread.

Andy

unread,
Sep 26, 2012, 1:41:31 AM9/26/12
to
在 2012年9月13日星期四UTC+8下午6时14分44秒,Andy写道:
> How to interrupt a task which is running in a thread? Just like Control+C is pressed. I don't mean kill the thread.

Nobody knows this?

Arjen Markus

unread,
Sep 26, 2012, 3:29:58 AM9/26/12
to
Could you be a bit more explicit about what you want to achieve?
Perhaps a small code example?

Control-C would terminate the entire process, but you do not want to kill
the thread. So - to me at least - it is unclear what you want.

Regards,

Arjen

Andy

unread,
Sep 26, 2012, 5:56:27 AM9/26/12
to
Hi Arjen

Thanks for your reply.
I have a Tk GUI app. There are "Start" and "Stop" buttons on my GUI. After pressing "Start" button, my app will execute a command in a thread, maybe copy a large file. It will take a long time. At the moment, I want to press "Stop" button to stop this action immidiately. And then, I can press "Start" button to copy that file again. This is what I want. Do you have any idea? Or is there another way to achieve this?

Arjen Markus

unread,
Sep 26, 2012, 6:37:43 AM9/26/12
to
There is no general way in which you can achieve that, as far as I know.
The only thing I can think of is that the task itself cooperates with you.
That is, if you take the copying example:
Some procedure copies chunks and looks regularly if it should continue.
If it sees it should interrupt the work, it saves whatever state needs saving
and returns control.

One possible mechanism to make this easier is the use of coroutines, but even
they require cooperation.

Perhaps http://wiki.tcl.tk/1526 holds some ideas you can use.

Regards,

Arjen

Gerald W. Lester

unread,
Sep 26, 2012, 9:07:39 AM9/26/12
to
First off, no need to use threads here at all.

Tcl/Tk event driven model will handle it. Take a look at the help/man pages
for the fcopy command. To stop the transfer, just close both files in the
procedure invoked by the "Stop" button.

--
+------------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+------------------------------------------------------------------------+

Asif

unread,
Sep 26, 2012, 5:28:40 PM9/26/12
to
Look at the trace command. It is used to generate an event. This will work with the event mechanism as mentioned by Gerald W. Lester. I'm wondering if will work when using threads. Hmm... event processing within the context of threads.

Andy

unread,
Sep 27, 2012, 10:15:38 PM9/27/12
to
在 2012年9月27日星期四UTC+8上午5时28分40秒,Asif写道:
> Look at the trace command. It is used to generate an event. This will work with the event mechanism as mentioned by Gerald W. Lester. I'm wondering if will work when using threads. Hmm... event processing within the context of threads.

I don't know how to trace a shared variable. This line of code doesn't work.

trace variable [ tsv::get app stop ] w MyTrace

Andy

unread,
Sep 27, 2012, 10:22:43 PM9/27/12
to
在 2012年9月26日星期三UTC+8下午6时37分45秒,Arjen Markus写道:
> On Wednesday, September 26, 2012 11:56:27 AM UTC+2, Andy wrote: > Hi Arjen > > > > Thanks for your reply. > > I have a Tk GUI app. There are "Start" and "Stop" buttons on my GUI. After pressing "Start" button, my app will execute a command in a thread, maybe copy a large file. It will take a long time. At the moment, I want to press "Stop" button to stop this action immidiately. And then, I can press "Start" button to copy that file again. This is what I want. Do you have any idea? Or is there another way to achieve this? There is no general way in which you can achieve that, as far as I know. The only thing I can think of is that the task itself cooperates with you. That is, if you take the copying example: Some procedure copies chunks and looks regularly if it should continue. If it sees it should interrupt the work, it saves whatever state needs saving and returns control. One possible mechanism to make this easier is the use of coroutines, but even they require cooperation. Perhaps http://wiki.tcl.tk/1526 holds some ideas you can use. Regards, Arjen

Seems very complicated...

Andy

unread,
Sep 27, 2012, 10:34:21 PM9/27/12
to
The task is still running even if I have released the thread.

package require Thread

set t1 [ thread::create {
proc test { } {
while {1} {
after 1000
puts hello
}
}
thread::wait
}]

thread::send -async $t1 [ list test ]

puts [ thread::names ]
after 3000

thread::release $t1
puts [ thread::names ]
vwait forever

Gerald W. Lester

unread,
Sep 28, 2012, 2:11:29 AM9/28/12
to
The example you cited before, file copy, does not require threads -- in
Tcl/Tk most things don't.

Tcl is not Java -- make use of the event loop or co-routines not threads.

Only use threads for things that either (a) block or (b) can/need to be done
in parallel (and you have multiple cores/cpus).

P.S. -- in the case of (b), it might be better to spawn off separate processes.

Andy

unread,
Sep 28, 2012, 2:56:55 AM9/28/12
to
在 2012年9月28日星期五UTC+8下午2时11分37秒,Gerald W. Lester写道:
> The example you cited before, file copy, does not require threads -- in Tcl/Tk most things don't. Tcl is not Java -- make use of the event loop or co-routines not threads. Only use threads for things that either (a) block or (b) can/need to be done in parallel (and you have multiple cores/cpus). P.S. -- in the case of (b), it might be better to spawn off separate processes. On 9/27/12 9:34 PM, Andy wrote: > The task is still running even if I have released the thread. > > package require Thread > > set t1 [ thread::create { > proc test { } { > while {1} { > after 1000 > puts hello > } > } > thread::wait > }] > > thread::send -async $t1 [ list test ] > > puts [ thread::names ] > after 3000 > > thread::release $t1 > puts [ thread::names ] > vwait forever > -- +------------------------------------------------------------------------+ | Gerald W. Lester, President, KNG Consulting LLC | | Email: Gerald...@kng-consulting.net | +------------------------------------------------------------------------+

Hi Gerald

But if I don't use thread, my GUI will be stuck. Could you give me an example?

Andy

unread,
Sep 28, 2012, 3:22:37 AM9/28/12
to
在 2012年9月28日星期五UTC+8下午2时11分37秒,Gerald W. Lester写道:
> The example you cited before, file copy, does not require threads -- in Tcl/Tk most things don't. Tcl is not Java -- make use of the event loop or co-routines not threads. Only use threads for things that either (a) block or (b) can/need to be done in parallel (and you have multiple cores/cpus). P.S. -- in the case of (b), it might be better to spawn off separate processes. On 9/27/12 9:34 PM, Andy wrote: > The task is still running even if I have released the thread. > > package require Thread > > set t1 [ thread::create { > proc test { } { > while {1} { > after 1000 > puts hello > } > } > thread::wait > }] > > thread::send -async $t1 [ list test ] > > puts [ thread::names ] > after 3000 > > thread::release $t1 > puts [ thread::names ] > vwait forever > -- +------------------------------------------------------------------------+ | Gerald W. Lester, President, KNG Consulting LLC | | Email: Gerald...@kng-consulting.net | +------------------------------------------------------------------------+

Hi Gerald

I just check fcopy command, indeed it can copy file in background. But I still want to find a common way to stop a task, maybe someday I will execute a java command or others, not just copy a large file.

Uwe Klein

unread,
Sep 28, 2012, 3:46:53 AM9/28/12
to
simple example:

#!/usr/bin/wish

button .start -text Start -command {handlecmd X start}
button .stop -text Stop -command {handlecmd X stop}
grid .start .stop

proc handlecmd {_id action} {
upvar ::$_id id
switch -- $action \
start {
if {![catch {set id} cerr]} {
puts stderr "Task runs already"
return
}
set id [ exec ping localhost & ]
} stop {
if {[catch {set id} cerr]} {
puts stderr "Task does not run"
return
}
exec kill $id
unset id
}
}

uwe

Andy

unread,
Sep 28, 2012, 6:20:48 AM9/28/12
to
在 2012年9月28日星期五UTC+8下午4时00分06秒,Uwe Klein写道:
> Andy wrote: > 在 2012年9月28日星期五UTC+8下午2时11分37秒,Gerald W. Lester写道: > >>The example you cited before, file copy, does not require threads -- in Tcl/Tk most things don't. Tcl is not Java -- make use of the event loop or co-routines not threads. Only use threads for things that either (a) block or (b) can/need to be done in parallel (and you have multiple cores/cpus). P.S. -- in the case of (b), it might be better to spawn off separate processes. On 9/27/12 9:34 PM, Andy wrote: > The task is still running even if I have released the thread. > > package require Thread > > set t1 [ thread::create { > proc test { } { > while {1} { > after 1000 > puts hello > } > } > thread::wait > }] > > thread::send -async $t1 [ list test ] > > puts [ thread::names ] > after 3000 > > thread::release $t1 > puts [ thread::names ] > vwait forever > -- +------------------------------------------------------------------------+ | Gerald W. Lester, President, KNG Consulting LLC | | Email: Gerald...@kng-consulting.net | +---------------------------------------------------- --------------------+ > > > Hi Gerald > > But if I don't use thread, my GUI will be stuck. Could you give me an example? simple example: #!/usr/bin/wish button .start -text Start -command {handlecmd X start} button .stop -text Stop -command {handlecmd X stop} grid .start .stop proc handlecmd {_id action} { upvar ::$_id id switch -- $action \ start { if {![catch {set id} cerr]} { puts stderr "Task runs already" return } set id [ exec ping localhost & ] } stop { if {[catch {set id} cerr]} { puts stderr "Task does not run" return } exec kill $id unset id } } uwe

Oh Uwe, thank you very much! I love you.

Andy

unread,
Sep 28, 2012, 6:36:10 AM9/28/12
to
在 2012年9月28日星期五UTC+8下午4时00分06秒,Uwe Klein写道:
> Andy wrote: > 在 2012年9月28日星期五UTC+8下午2时11分37秒,Gerald W. Lester写道: > >>The example you cited before, file copy, does not require threads -- in Tcl/Tk most things don't. Tcl is not Java -- make use of the event loop or co-routines not threads. Only use threads for things that either (a) block or (b) can/need to be done in parallel (and you have multiple cores/cpus). P.S. -- in the case of (b), it might be better to spawn off separate processes. On 9/27/12 9:34 PM, Andy wrote: > The task is still running even if I have released the thread. > > package require Thread > > set t1 [ thread::create { > proc test { } { > while {1} { > after 1000 > puts hello > } > } > thread::wait > }] > > thread::send -async $t1 [ list test ] > > puts [ thread::names ] > after 3000 > > thread::release $t1 > puts [ thread::names ] > vwait forever > -- +------------------------------------------------------------------------+ | Gerald W. Lester, President, KNG Consulting LLC | | Email: Gerald...@kng-consulting.net | +---------------------------------------------------- --------------------+ > > > Hi Gerald > > But if I don't use thread, my GUI will be stuck. Could you give me an example? simple example: #!/usr/bin/wish button .start -text Start -command {handlecmd X start} button .stop -text Stop -command {handlecmd X stop} grid .start .stop proc handlecmd {_id action} { upvar ::$_id id switch -- $action \ start { if {![catch {set id} cerr]} { puts stderr "Task runs already" return } set id [ exec ping localhost & ] } stop { if {[catch {set id} cerr]} { puts stderr "Task does not run" return } exec kill $id unset id } } uwe

Hi Uwe
Another question, how to get output message? I mean the message generated by ping command.

Uwe Klein

unread,
Sep 28, 2012, 6:58:39 AM9/28/12
to
Andy wrote:
> Another question, how to get output message? I mean the message generated by ping command.

#!/usr/bin/wish

button .start -text Start -command {handlecmd X start}
button .stop -text Stop -command {handlecmd X stop}
grid .start .stop

# create a loop filedescriptor, there are various other ways
# to achieve the same:
set ::pfd [open |cat RDWR ]
fconfigure $::pfd -buffering none

# create an event handler for (returning) output
# and a proc to handle events:
proc outputevent {fd} {
puts stderr PFD:[ gets $fd ]
}
fileevent $::pfd readable [list outputevent $::pfd]

proc handlecmd {_id action} {
upvar ::$_id id
switch -- $action \
start {
if {![catch {set id} cerr]} {
puts stderr "Task runs already"
return
}
# redirect all output to a file desciptor:
set id [ exec ping localhost >&@ $::pfd & ]

Gerald W. Lester

unread,
Sep 28, 2012, 9:29:54 AM9/28/12
to
Andy,

There is no general answer -- threads or no threads. Some things are
autonomic operations -- i.e. most OS calls. Most languages just lie to you.

Andy

unread,
Sep 28, 2012, 11:41:18 PM9/28/12
to
在 2012年9月28日星期五UTC+8下午7时00分04秒,Uwe Klein写道:
> Andy wrote: > Another question, how to get output message? I mean the message generated by ping command. #!/usr/bin/wish button .start -text Start -command {handlecmd X start} button .stop -text Stop -command {handlecmd X stop} grid .start .stop # create a loop filedescriptor, there are various other ways # to achieve the same: set ::pfd [open |cat RDWR ] fconfigure $::pfd -buffering none # create an event handler for (returning) output # and a proc to handle events: proc outputevent {fd} { puts stderr PFD:[ gets $fd ] } fileevent $::pfd readable [list outputevent $::pfd] proc handlecmd {_id action} { upvar ::$_id id switch -- $action \ start { if {![catch {set id} cerr]} { puts stderr "Task runs already" return } # redirect all output to a file desciptor: set id [ exec ping localhost >&@ $::pfd & ] } stop { if {[catch {set id} cerr]} { puts stderr "Task does not run" return } exec kill $id unset id } } uwe

Hi Uwe
I run this code in Windows 7, but got nothing. Is there something wrong?

set ::pfd [open |ping RDWR]
fconfigure $::pfd -buffering none

proc outputevent {fd} {
set data [ read $fd nonewline ]
puts $data
}

fileevent $::pfd readable [list outputevent $::pfd]


proc handlecmd {_id action} {
upvar ::$_id id
switch -- $action {
start {
if {![catch {set id} cerr]} {
puts stderr "Task runs already"
return
}
set id [ exec ping localhost >&@ $::pfd & ]
}
stop {
if {[catch {set id} cerr]} {
puts stderr "Task does not run"
return
}
exec taskkill /F /PID $id
unset id
}
}
}

handlecmd X start

Uwe Klein

unread,
Sep 29, 2012, 4:20:03 AM9/29/12
to
Andy wrote:
> 在 2012年9月28日星期五UTC+8下午7时00分04秒,Uwe Klein写道:
>
>>Andy wrote: > Another question, how to get output message? I mean the message generated by ping command. #!/usr/bin/wish button .start -text Start -command {handlecmd X start} button .stop -text Stop -command {handlecmd X stop} grid .start .stop # create a loop filedescriptor, there are various other ways # to achieve the same: set ::pfd [open |cat RDWR ] fconfigure $::pfd -buffering none # create an event handler for (returning) output # and a proc to handle events: proc outputevent {fd} { puts stderr PFD:[ gets $fd ] } fileevent $::pfd readable [list outputevent $::pfd] proc handlecmd {_id action} { upvar ::$_id id switch -- $action \ start { if {![catch {set id} cerr]} { puts stderr "Task runs already" return } # redirect all output to a file desciptor: set id [ exec ping localhost >&@ $::pfd & ] } stop { if {[catch {set id} cerr]} { puts stderr "Task does not run" return } exec kill $id unset id } } uwe
>
>
> Hi Uwe
> I run this code in Windows 7, but got nothing. Is there something wrong?
>
There is no 'cat' on windows. ( obviously, it is an inferior platform ;-)
if you use tcl 8.6 onwards you can replace it with
earlier? use [pipe] from tclx package

foreach {::rpfd ::wpfd } [chan pipe] break

# set ::pfd [open |ping RDWR]
# fconfigure $::pfd -buffering none
>
> proc outputevent {fd} {
> set data [ read $fd nonewline ]
> puts $data
> }
>
fileevent $::rpfd readable [list outputevent $::rpfd]
>
>
> proc handlecmd {_id action} {
> upvar ::$_id id
> switch -- $action {
> start {
> if {![catch {set id} cerr]} {
> puts stderr "Task runs already"
> return
> }
set id [ exec ping localhost >&@ $::wpfd & ]
> }
> stop {
> if {[catch {set id} cerr]} {
> puts stderr "Task does not run"
> return
> }
> exec taskkill /F /PID $id
> unset id
> }
> }
> }
>
> handlecmd X start


uwe

Andy

unread,
Sep 29, 2012, 5:29:51 AM9/29/12
to
在 2012年9月29日星期六UTC+8下午4时21分17秒,Uwe Klein写道:
> Andy wrote: > 在 2012年9月28日星期五UTC+8下午7时00分04秒,Uwe Klein写道: > >>Andy wrote: > Another question, how to get output message? I mean the message generated by ping command. #!/usr/bin/wish button .start -text Start -command {handlecmd X start} button .stop -text Stop -command {handlecmd X stop} grid .start .stop # create a loop filedescriptor, there are various other ways # to achieve the same: set ::pfd [open |cat RDWR ] fconfigure $::pfd -buffering none # create an event handler for (returning) output # and a proc to handle events: proc outputevent {fd} { puts stderr PFD:[ gets $fd ] } fileevent $::pfd readable [list outputevent $::pfd] proc handlecmd {_id action} { upvar ::$_id id switch -- $action \ start { if {![catch {set id} cerr]} { puts stderr "Task runs already" return } # redirect all output to a file desciptor: set id [ exec ping localhost >&@ $::pfd & ] } stop { if {[catch {set id} cerr]} { puts stderr "Task does not run" return } exec kill $id unset id } } uwe > > > Hi Uwe > I run this code in Windows 7, but got nothing. Is there something wrong? > There is no 'cat' on windows. ( obviously, it is an inferior platform ;-) if you use tcl 8.6 onwards you can replace it with earlier? use [pipe] from tclx package foreach {::rpfd ::wpfd } [chan pipe] break # set ::pfd [open |ping RDWR] # fconfigure $::pfd -buffering none > > proc outputevent {fd} { > set data [ read $fd nonewline ] > puts $data > } > fileevent $::rpfd readable [list outputevent $::rpfd] > > > proc handlecmd {_id action} { > upvar ::$_id id > switch -- $action { > start { > if {![catch {set id} cerr]} { > puts stderr "Task runs already" > return > } set id [ exec ping localhost >&@ $::wpfd & ] > } > stop { > if {[catch {set id} cerr]} { > puts stderr "Task does not run" > return > } > exec taskkill /F /PID $id > unset id > } > } > } > > handlecmd X start uwe

Great! It works. If I want to see the output, I must add this line of code:

vwait forever

Thanks Uwe, and thank you all.

Donal K. Fellows

unread,
Oct 3, 2012, 5:51:28 AM10/3/12
to
On 29/09/2012 09:20, Uwe Klein wrote:
> foreach {::rpfd ::wpfd } [chan pipe] break

If you have [chan pipe], you also definitely have [lassign]:

lassign [chan pipe] rpfd wpfd

Donal.
0 new messages