• Tk generate an exec sequence in background ???

    From my DIY@21:1/5 to All on Sun Dec 11 12:50:31 2022
    Hello,

    I'm pretty new to TCL/TK and this time it's too much for me !

    I did a Tk GUI where I can select several actions with check boxes and then when I click on a button I want all those actions to be executed in background but keeping the actions order.

    So let's say I've checkboxes action1, action2 and action3.
    For now I have somewhere in the button's proc the following lines :

    if { ${action1_checked} } {
    exec prog1 &
    }

    if { ${action2_checked} } {
    exec prog2 &
    }

    if { ${action3_checked} } {
    exec prog3 &
    }

    So the thing is that all selected actions are launched simultaneously and they each end anytime, conclusion is that I'm loosing the fact that action3 must be launched after action2 ends which must be launched after action1 ends.

    I googled a lot of things, got several answers I'm not able to understand because too advanced for me !

    So if someone could provide me specific info to this case I would be grateful !

    Thanks.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From my DIY@21:1/5 to All on Sun Dec 11 13:46:29 2022
    Hello Helmut,

    Thank you for your answer.

    In fact I need these actions to be run in background as they can be pretty long and I need to still have access in the TK GUI to other buttons that can launch other actions !

    If I remember well when I do not use the & the GUI is not usable until actions are done !

    Thanks.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Helmut Giese@21:1/5 to All on Sun Dec 11 22:41:21 2022
    Hello,
    if { ${action1_checked} } {
    exec prog1 &
    }

    if { ${action2_checked} } {
    exec prog2 &
    }

    if { ${action3_checked} } {
    exec prog3 &
    }

    So the thing is that all selected actions are launched simultaneously and they each end anytime, conclusion is that I'm loosing the fact that action3 must be launched after action2 ends which must be launched after action1 ends.

    I think you should remove the &s at the end of your 'exec' calls. If
    you do Tcl will only (re-) gain control when the 'exec' operation is
    finished and can then start the next - which is what I have understood
    to be what you want.
    HTH
    Helmut

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to my DIY on Sun Dec 11 22:45:10 2022
    my DIY <[email protected]> wrote:
    Hello,

    I'm pretty new to TCL/TK and this time it's too much for me !

    I did a Tk GUI where I can select several actions with check boxes
    and then when I click on a button I want all those actions to be
    executed in background but keeping the actions order.

    So let's say I've checkboxes action1, action2 and action3. For now I
    have somewhere in the button's proc the following lines :

    if { ${action1_checked} } {
    exec prog1 &
    }

    if { ${action2_checked} } {
    exec prog2 &
    }

    if { ${action3_checked} } {
    exec prog3 &
    }

    So the thing is that all selected actions are launched simultaneously
    and they each end anytime, conclusion is that I'm loosing the fact
    that action3 must be launched after action2 ends which must be
    launched after action1 ends.

    You are receiving exactly what you coded for above. Each program is independently launched in the background, without regard for the
    others.

    I googled a lot of things, got several answers I'm not able to
    understand because too advanced for me !

    So if someone could provide me specific info to this case I would be
    grateful !

    One option you have already been given, and it is the simplest of the
    options. Just remove the ampersands and you get sequential serial
    processing.

    A second option is to modify your background program to be launched
    once, but itself take options to indcate what to run:

    exec prog --action1 --action2 --action3 &

    And have it run the requested actions in sequence.

    A third option is to create a TCL wrapper script that actually runs the
    prog1 through prog3 programs, and accepts options like I suggested
    above, then you launch the wrapper and it launches the progs in order.
    I.e., something like this as the TCL wrapper:

    foreach {arg prog} [list --action1 prog1 --action2 prog2] {
    if {$arg in $argv} {
    exec $prog
    }
    }

    A fourth option, if you are on Linux/BSD/MacOS, is to create a shell
    script that does what the bit of TCL above does. And then launch that
    shell script.

    The next level up in complexity is you'll have to create some TCL event
    driven code to use TCL's 'open' command to launch each task, and
    fileevent to watch the returning file descriptors for each to finish
    before launching the next. I'm not going to try to diagram that here,
    as I'll likely have written out several bugs from just typing code in
    off the top of my head.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bezoar@21:1/5 to my DIY on Sun Dec 11 23:34:36 2022
    On Sunday, December 11, 2022 at 2:50:34 PM UTC-6, my DIY wrote:
    Hello,

    I'm pretty new to TCL/TK and this time it's too much for me !

    I did a Tk GUI where I can select several actions with check boxes and then when I click on a button I want all those actions to be executed in background but keeping the actions order.

    So let's say I've checkboxes action1, action2 and action3.
    For now I have somewhere in the button's proc the following lines :

    if { ${action1_checked} } {
    exec prog1 &
    }

    if { ${action2_checked} } {
    exec prog2 &
    }

    if { ${action3_checked} } {
    exec prog3 &
    }

    So the thing is that all selected actions are launched simultaneously and they each end anytime, conclusion is that I'm loosing the fact that action3 must be launched after action2 ends which must be launched after action1 ends.

    I googled a lot of things, got several answers I'm not able to understand because too advanced for me !

    So if someone could provide me specific info to this case I would be grateful !

    Thanks.


    #!/bin/sh
    # the next line restarts using wish \
    exec /opt/usr8.6.3/bin/tclsh8.6 "$0" ${1+"$@"}
    package require Tk
    namespace eval WaitFd {
    proc WaitFdReader { fd } {
    if { [eof $fd ] } {
    catch { close $fd }
    incr ::forever_$fd;
    } else {
    read $fd; # we dont care about output
    }
    }
    proc wait { fd } {
    fconfigure $fd -blocking 0
    fileevent $fd readable [list WaitFd::WaitFdReader $fd ]
    set w ::forever_$fd
    vwait $w
    unset $w
    }
    namespace export WaitFdReader
    }
    pack [button .ls -text "background" -command {
    # run two commands in background we wait until one is done before running second
    # dont have xpdf or a pdf file try some long running process or one where user must quit
    # using open rather than exec
    set out [ open "|xpdf untitled.pdf &" "r" ];
    WaitFd::wait $out
    set out [ open "|xpdf important.pdf &" "r" ]
    WaitFd::wait $out
    } ] -side top -fill x -padx 10 -pady 10
    # while the background tasks are running press the dummy button to see that
    # Tk is still alive ( handling events)
    pack [button .dummy -text "Press Me" -command {
    puts "You Pressed Me!"
    } ] -side top -fill x -padx 10 -pady 10

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Schelte@21:1/5 to Bezoar on Mon Dec 12 17:22:53 2022
    On 12/12/2022 08:34, Bezoar wrote:
    On Sunday, December 11, 2022 at 2:50:34 PM UTC-6, my DIY wrote:
    I did a Tk GUI where I can select several actions with check boxes and then when I click on a button I want all those actions to be executed in background but keeping the actions order.

    Because vwaits nest, I prefer to use them sparingly. They are not needed
    here. You can just store the commands in a list and when one command
    finishes, start the next:

    #!/usr/bin/env tclsh

    proc log {str} {
    # Simplistic logging
    puts $str
    }

    proc serialexec {args} {
    variable serialexec
    lappend serialexec $args
    log "Queued command: $args"
    if {[llength $serialexec] == 1} {
    # First command can immediately be started
    serialrun
    }
    }

    proc serialrun {} {
    variable serialexec
    set cmd [lindex $serialexec 0]
    set fd [open "|$cmd 2>@1"]
    log "Started command: $cmd, pid = [pid $fd]"
    fconfigure $fd -blocking 0
    fileevent $fd readable [list callback $fd]
    }

    proc callback {fd} {
    if {[eof $fd]} {
    variable serialexec
    # The channel must be blocking to get the exit code
    fconfigure $fd -blocking 1
    try {
    close $fd
    set retcode 0
    } trap {CHILDSTATUS} {err info} {
    set retcode [lindex [dict get $info -errorcode] end]
    } on error {err info} {
    # Something unexpected happened
    log $err
    exit
    }
    set serialexec [lassign $serialexec cmd]
    log "Command finished: $cmd, exit code = $retcode"
    if {[llength $serialexec]} {
    # Start the next queued command
    serialrun
    } else {
    # All commands have finished
    exit
    }
    } else {
    if {[gets $fd line] >= 0} {
    # Optionally log the output of the command
    log $line
    }
    }
    }

    serialexec sleep 5
    serialexec sleep 3
    serialexec sleep 4

    vwait forever

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Bezoar@21:1/5 to Schelte on Mon Dec 12 12:59:45 2022
    On Monday, December 12, 2022 at 10:22:58 AM UTC-6, Schelte wrote:
    On 12/12/2022 08:34, Bezoar wrote:
    On Sunday, December 11, 2022 at 2:50:34 PM UTC-6, my DIY wrote:
    I did a Tk GUI where I can select several actions with check boxes and then when I click on a button I want all those actions to be executed in background but keeping the actions order.
    Because vwaits nest, I prefer to use them sparingly. They are not needed here. You can just store the commands in a list and when one command finishes, start the next:

    #!/usr/bin/env tclsh

    proc log {str} {
    # Simplistic logging
    puts $str
    }

    proc serialexec {args} {
    variable serialexec
    lappend serialexec $args
    log "Queued command: $args"
    if {[llength $serialexec] == 1} {
    # First command can immediately be started
    serialrun
    }
    }

    proc serialrun {} {
    variable serialexec
    set cmd [lindex $serialexec 0]
    set fd [open "|$cmd 2>@1"]
    log "Started command: $cmd, pid = [pid $fd]"
    fconfigure $fd -blocking 0
    fileevent $fd readable [list callback $fd]
    }

    proc callback {fd} {
    if {[eof $fd]} {
    variable serialexec
    # The channel must be blocking to get the exit code
    fconfigure $fd -blocking 1
    try {
    close $fd
    set retcode 0
    } trap {CHILDSTATUS} {err info} {
    set retcode [lindex [dict get $info -errorcode] end]
    } on error {err info} {
    # Something unexpected happened
    log $err
    exit
    }
    set serialexec [lassign $serialexec cmd]
    log "Command finished: $cmd, exit code = $retcode"
    if {[llength $serialexec]} {
    # Start the next queued command
    serialrun
    } else {
    # All commands have finished
    exit
    }
    } else {
    if {[gets $fd line] >= 0} {
    # Optionally log the output of the command
    log $line
    }
    }
    }

    serialexec sleep 5
    serialexec sleep 3
    serialexec sleep 4

    vwait forever
    This is a better idea.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From my DIY@21:1/5 to All on Mon Dec 12 13:22:22 2022
    Hi,

    Ok, thank you all for your proposals !

    Special big thanks to Bezoar, your solution works exactly as I needed and it fits in 2 little procs !!
    I still don't understood everything yet but it's a good start ! :-)

    Thank you again !

    Stephane.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)