• Re: Non GUI blocking code

    From Rich@21:1/5 to Shaun Kulesa on Wed Apr 19 15:55:52 2023
    Shaun Kulesa <shaunkulesa@gmail.com> wrote:
    I have two functions in a namespace (InstallPage), the second
    function that I execute "unzip" makes the program window not respond
    for a short period of time (about 10 seconds).

    I've tried using threads and pools but I couldn't pass variables to
    them, how could I execute these functions without blocking the
    windows events?

    Threads are your best bet, and you pass variables to threads either as
    a parameter to the 'thread::send' command, or by using the tsv (thread
    shared variables) to pass the data.

    For a simple unzip, simply passing the variable contents as parameters
    of thread::send is easiest.

    Otherwise you will have to write your own unzip that performs the work
    of unzipping in small chunks, while allowing the event loop to run in
    between each small chunk of work.

    Say you had a thread who's handle is in $tid, and inside it has an
    'unzip' proc that takes the same parameters as your code example.
    You'd call the unzip in the thread from your main code like so:

    thread::send $tid [list unzip $location $version $status_list_box]

    Look up the -async option if you want to actually launch this 'in the background'. The above version will be synchronous with your code, but
    I think the event loop will still be allowed to run (test it yourself
    and see).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 08:19:30 2023
    I have two functions in a namespace (InstallPage), the second function that I execute "unzip" makes the program window not respond for a short period of time (about 10 seconds).

    I've tried using threads and pools but I couldn't pass variables to them, how could I execute these functions without blocking the windows events?

    I would appreciate code as well as manual pages as I have been using manual pages but I cannot seem to get the code right.

    ```tcl
    proc install {version filelocation} {
    set version [get_version]
    set location [get_location]

    set status_list_box [listbox .install_frame.status_list_box -width 80 -height 10]
    grid $status_list_box -row 2 -column 0 -columnspan 2 -sticky news

    $status_list_box insert end "Downloading Tcl $version in $location"

    download $location $version $status_list_box
    unzip $location $version $status_list_box
    }

    proc download {location version status_list_box} {
    set f [open "$location\\Tcl.zip" wb]
    set tok [http::geturl $version -channel $f -binary 1]
    close $f

    if {[http::status $tok] eq "ok" && [http::ncode $tok] == 200} {
    $status_list_box insert end "Downloaded successfully"
    }

    http::cleanup $tok
    }

    proc unzip {location version status_list_box} {
    $status_list_box insert end "Installing Tcl $version in $location"

    ::zipfile::decode::open $location\\Tcl.zip

    $status_list_box insert end "Extracting files to $location"
    set archiveDict [::zipfile::decode::archive]
    ::zipfile::decode::unzip $archiveDict $location
    ::zipfile::decode::close

    $status_list_box insert end "Installed successfully"
    }
    ```

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Shaun Kulesa on Wed Apr 19 17:10:08 2023
    Shaun Kulesa <shaunkulesa@gmail.com> wrote:
    Oh thank you so much, I was passing the variables wrong earlier as
    you have shown me.

    I was doing it like this earlier - thread::send -async
    $download_thread {"download $location $version $status_list_box"}

    Ah, that won't work. Note from 'man Tcl' that curly brackets {}
    prevent variable expansion (and command substitution) on the string
    inside. You would have been attempting to run a proc named:

    "download $location $version $status_list_box"

    Quotes included.

    When generating calls to procedures using [list] to generate the calls
    is best, it provides proper quoting to maintain separate parameters
    through the calling proceess.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 09:42:30 2023
    Oh thank you so much, I was passing the variables wrong earlier as you have shown me.

    I was doing it like this earlier - thread::send -async $download_thread {"download $location $version $status_list_box"}

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert Heller@21:1/5 to Rich on Wed Apr 19 16:20:03 2023
    At Wed, 19 Apr 2023 15:55:52 -0000 (UTC) Rich <rich@example.invalid> wrote:


    Shaun Kulesa <shaunkulesa@gmail.com> wrote:
    I have two functions in a namespace (InstallPage), the second
    function that I execute "unzip" makes the program window not respond
    for a short period of time (about 10 seconds).

    I've tried using threads and pools but I couldn't pass variables to
    them, how could I execute these functions without blocking the
    windows events?

    Threads are your best bet, and you pass variables to threads either as
    a parameter to the 'thread::send' command, or by using the tsv (thread
    shared variables) to pass the data.

    For a simple unzip, simply passing the variable contents as parameters
    of thread::send is easiest.

    Otherwise you will have to write your own unzip that performs the work
    of unzipping in small chunks, while allowing the event loop to run in
    between each small chunk of work.

    Say you had a thread who's handle is in $tid, and inside it has an
    'unzip' proc that takes the same parameters as your code example.
    You'd call the unzip in the thread from your main code like so:

    thread::send $tid [list unzip $location $version $status_list_box]

    Look up the -async option if you want to actually launch this 'in the background'. The above version will be synchronous with your code, but
    I think the event loop will still be allowed to run (test it yourself
    and see).

    Another (maybe easier?) option is to use a pipe and ansyc reads (fileevent):

    proc upzipbackground {zipfile}
    ## -qq tells unzip to be real quiet: no output, unless there is an error
    if {[catch {open "|unzip -qq $zipfile" r} unzippipe]} {
    # error starting unzip
    tk_messageBox -icon error -type ok -message "Failed to unzip $zipfile: $unzippipe"
    } else {
    fileevent $unzippipe readable [list upzippiperead $unzippipe]
    }
    }

    proc upzippiperead {pipe} {
    if {[gets $pipe line] < 0} {
    catch {close $pipe} result
    tk_messageBox -icon info -type ok -message "Unzip completed: $result"
    } else {
    # maybe do something with $line
    }
    }






    --
    Robert Heller -- Cell: 413-658-7953 GV: 978-633-5364
    Deepwoods Software -- Custom Software Services
    http://www.deepsoft.com/ -- Linux Administration Services
    heller@deepsoft.com -- Webhosting Services

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Shaun Kulesa on Wed Apr 19 10:42:18 2023
    On 4/19/2023 8:19 AM, Shaun Kulesa wrote:
    I have two functions in a namespace (InstallPage), the second function that I execute "unzip" makes the program window not respond for a short period of time (about 10 seconds).

    I've tried using threads and pools but I couldn't pass variables to them, how could I execute these functions without blocking the windows events?

    I would appreciate code as well as manual pages as I have been using manual pages but I cannot seem to get the code right.

    ```tcl
    proc install {version filelocation} {
    set version [get_version]
    set location [get_location]

    set status_list_box [listbox .install_frame.status_list_box -width 80 -height 10]
    grid $status_list_box -row 2 -column 0 -columnspan 2 -sticky news

    $status_list_box insert end "Downloading Tcl $version in $location"

    download $location $version $status_list_box
    unzip $location $version $status_list_box
    }

    proc download {location version status_list_box} {
    set f [open "$location\\Tcl.zip" wb]
    set tok [http::geturl $version -channel $f -binary 1]
    close $f

    if {[http::status $tok] eq "ok" && [http::ncode $tok] == 200} {
    $status_list_box insert end "Downloaded successfully"
    }

    http::cleanup $tok
    }

    proc unzip {location version status_list_box} {
    $status_list_box insert end "Installing Tcl $version in $location"

    ::zipfile::decode::open $location\\Tcl.zip

    $status_list_box insert end "Extracting files to $location"
    set archiveDict [::zipfile::decode::archive]
    ::zipfile::decode::unzip $archiveDict $location
    ::zipfile::decode::close

    $status_list_box insert end "Installed successfully"
    }
    ```

    I agree with Rich, your best bet is to use the threads
    package. However, there is a fair amount of learning required
    to use this approach.

    I am not familiar with the zipfile code you are using. Do you
    need to do some [package require zipfile] on that?

    If so, then keep in mind that packages loaded in the main
    thread do not automatically load into a new thread. There is
    ttrace for that. I don't use ttrace myself, and so I can't
    help with that.

    Without using ttrace, you could do a [package require zipfile]
    in your thread's init script using thread::create, with some
    procs to call, and a thread::wait at the end. Then you could
    use thread::send as shown in Rich's post.

    The GUI is being built in your main thread, and so in order to
    do the inserts from another thread, you would have to do a
    thread::send back to the main thread sending $status_list_box.
    Care would be needed here to avoid a deadlock.

    The proc unzip is also puzzling to me. I would have expected
    to see some return handle on the open.

    Also, you don't show any error code. What if the zip open fails?

    Personally, I would re-structure the unzip as (pseudo code):

    notify starting in listbox in main thread
    set status [do the unzip in another thread, and wait]
    notify $status in main thread

    And have the unzip code in the thread do a catch around the
    parts that can fail returning a status. This would eliminate
    the issue with the notify being in the separate thread.

    But being done in the separate thread leaves the mainthread
    gui able to process events.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 11:03:36 2023
    I don't have a return message as I can't currently get that to work as it will vwait for the return variable but if I print it then it will say it cannot find the variable.

    The code below will get to "puts $download_return" and give the error:

    Error:

    can't read "download_return": no such variable
    while executing
    "puts $download_return"

    Code:

    set download_thread [thread::create {
    proc download {location version status_list_box} {
    return message "Downloaded successfully"
    }

    thread::wait
    }]

    thread::send -async $download_thread [list download $location $version $status_list_box] download_return

    vwait download_return
    puts $download_return

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 11:36:32 2023
    Sorry, I left that in when changing it from:

    set message "Downloaded successfully"

    The set didn't work either.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to All on Wed Apr 19 11:38:17 2023
    On 4/19/2023 11:24 AM, et99 wrote:
    On 4/19/2023 11:03 AM, Shaun Kulesa wrote:
    I don't have a return message as I can't currently get that to work as it will vwait for the return variable but if I print it then it will say it cannot find the variable.

    The code below will get to "puts $download_return" and give the error:

    Error:

    can't read "download_return": no such variable
         while executing
    "puts $download_return"

    Code:

    set download_thread [thread::create {
         proc download {location version status_list_box} {
             return message "Downloaded successfully"
         }

         thread::wait
    }]

    thread::send -async $download_thread [list download $location $version $status_list_box] download_return

    vwait download_return
    puts $download_return

    as shown,

    return message "Downloaded successfully"

    should fail

    sorry, actually, it doesn't fail, but doesn't return the text string,

    so not sure what it does, seems return can take any number of args

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Shaun Kulesa on Wed Apr 19 11:24:54 2023
    On 4/19/2023 11:03 AM, Shaun Kulesa wrote:
    I don't have a return message as I can't currently get that to work as it will vwait for the return variable but if I print it then it will say it cannot find the variable.

    The code below will get to "puts $download_return" and give the error:

    Error:

    can't read "download_return": no such variable
    while executing
    "puts $download_return"

    Code:

    set download_thread [thread::create {
    proc download {location version status_list_box} {
    return message "Downloaded successfully"
    }

    thread::wait
    }]

    thread::send -async $download_thread [list download $location $version $status_list_box] download_return

    vwait download_return
    puts $download_return

    as shown,

    return message "Downloaded successfully"

    should fail

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 14:03:36 2023
    It works now, I should take breaks when coding, I must have done something silly which caused an error.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From saitology9@21:1/5 to Shaun Kulesa on Wed Apr 19 17:05:04 2023
    On 4/19/2023 11:19 AM, Shaun Kulesa wrote:
    I have two functions in a namespace (InstallPage), the second function that I execute "unzip" makes the program window not respond for a short period of time (about 10 seconds).

    I've tried using threads and pools but I couldn't pass variables to them, how could I execute these functions without blocking the windows events?

    I would appreciate code as well as manual pages as I have been using manual pages but I cannot seem to get the code right.


    Do you have this working as it should? My suggestion would be to first
    make sure it works in normal/traditional/single-threaded way - not sure
    what to call it. Otherwise, even simplest mistakes would be that much
    harder to detect and fix when you move to threads.

    I think the slowdown is in the http code and not the unzipping. I
    believe the http call has an asynch option which presumably implies
    background processing so that may be an easier option for you.

    Otherwise, once you have the basic version working, you can then move on
    to threads and send it commands as in rich's example.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to Shaun Kulesa on Wed Apr 19 14:13:40 2023
    On Wednesday, April 19, 2023 at 2:03:39 PM UTC-7, Shaun Kulesa wrote:
    It works now, I should take breaks when coding, I must have done something silly which caused an error.

    I like to use lamda functions with GUI+thread combinations. This way, all the code that is local to the function is still in that function. (this example is untested, but should give you the basic idea):

    proc unzip_background {location version status_list_box} {
    $status_list_box insert end "Installing Tcl $version in $location"

    thread::send $tid -async apply {{location version status_list_box mainid} {
    package require zipfile
    ::zipfile::decode::open $location\\Tcl.zip
    thread send $mainid -async $status_list_box insert end "Extracting files to $location"
    set archiveDict [::zipfile::decode::archive]
    ::zipfile::decode::unzip $archiveDict $location
    ::zipfile::decode::close
    thread send $mainid -async $status_list_box insert end "Installed successfully"
    }} $location $version $status_list_box [thread::id]
    }

    It also removes the burden of loading code into the thread(s).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 14:16:36 2023
    When I said - "It works now, I should take breaks when coding, I must have done something silly which caused an error.", that was when I just tested it in the global code execution area. If I have it in my namespace it won't find the variable.

    When I put $download_return on that last line, it won't find the variable, this only happens when I have it in a namespace.

    namespace eval InstallPage {
    namespace import ::VersionPage::*
    namespace import ::LocationPage::*

    proc create_gui {} {
    ...
    }

    proc install {version filelocation} {
    set version [get_version]
    set location [get_location]

    set status_list_box [listbox .install_frame.status_list_box -width 80 -height 10]
    grid $status_list_box -row 2 -column 0 -columnspan 2 -sticky news

    $status_list_box insert end "Downloading Tcl $version in $location"

    set download_thread [thread::create {
    proc download {location version status_list_box} {
    return "Downloaded successfully"
    }

    thread::wait
    }]

    thread::send -async $download_thread [list download $location $version $status_list_box] download_return

    vwait download_return
    puts $download_return

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to Shaun Kulesa on Wed Apr 19 14:33:06 2023
    On Wednesday, April 19, 2023 at 2:16:38 PM UTC-7, Shaun Kulesa wrote:
    When I said - "It works now, I should take breaks when coding, I must have done something silly which caused an error.", that was when I just tested it in the global code execution area. If I have it in my namespace it won't find the variable.

    When I put $download_return on that last line, it won't find the variable, this only happens when I have it in a namespace.

    namespace eval InstallPage {
    namespace import ::VersionPage::*
    namespace import ::LocationPage::*

    proc create_gui {} {
    ...
    }

    proc install {version filelocation} {
    set version [get_version]
    set location [get_location]

    set status_list_box [listbox .install_frame.status_list_box -width 80 -height 10]
    grid $status_list_box -row 2 -column 0 -columnspan 2 -sticky news

    $status_list_box insert end "Downloading Tcl $version in $location"
    set download_thread [thread::create {
    proc download {location version status_list_box} {
    return "Downloaded successfully"
    }

    thread::wait
    }]

    thread::send -async $download_thread [list download $location $version $status_list_box] download_return

    vwait download_return
    puts $download_return

    As long as there are [vwait] or [thread::wait] statements in the code, there will continue to be blocking periods during execution where the gui will be unresponsive.

    You have to think in terms of event sequences, where one event then causes another event, and so on. Sequential code should never wait for anything.

    My $0.02,
    -Brian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 14:46:55 2023
    I'll try it your way... I need to fully understand it first.

    I'm not sure what the $mainid is, are you creating a thread inside another thread and passing information from the child thread to the parent thread?
    And if you doing that, what portion of the code is in the parent thread?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to Shaun Kulesa on Wed Apr 19 14:57:52 2023
    On Wednesday, April 19, 2023 at 2:46:58 PM UTC-7, Shaun Kulesa wrote:
    I'll try it your way... I need to fully understand it first.

    I'm not sure what the $mainid is, are you creating a thread inside another thread and passing information from the child thread to the parent thread?
    And if you doing that, what portion of the code is in the parent thread?

    No, not a thread within a thread.
    The GUI thread (i.e. the main program) is passing a function description and arguments to another thread to evaluate. One of those arguments is the id of the initiating thread. When the remote thread is done, its last step is to send a command back to
    the calling thread.

    The [apply] command takes the given block of code and executes it passing the arguments given at the end of the command. The "mainid" argument is passed in as [thread::id], i.e., the id of the thread executing the thread::send command. Yes, it is a
    brain twister.

    The [unzip_background] proc is creating an event in a worker thread to do some work.
    The worker thread, after doing the work, is creating event back in the main thread to indicate the work is done.

    -Brian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Shaun Kulesa on Wed Apr 19 22:02:23 2023
    Shaun Kulesa <shaunkulesa@gmail.com> wrote:
    I'll try it your way... I need to fully understand it first.

    I'm not sure what the $mainid is,

    Look at the code. mainid is a parameter variable to the lambda. It
    gets its value from the call to thread::id near the bottom. So it
    receives the thread identifier of the thread where the thread::send
    call is performed.

    are you creating a thread inside another thread and passing
    information from the child thread to the parent thread?

    No. Just a second thread. But it passes in the thread identifier of
    the thread making the call, so the background thread can cause an
    action to happen in the caller, when the unzip finishes.

    And if you doing that, what portion of the code is in the parent
    thread?

    All of the code in the lambda exeutes in the background thread.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Wed Apr 19 15:10:47 2023
    The undefined variable $tid is what is confusing me.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Shaun Kulesa on Wed Apr 19 15:45:01 2023
    On 4/19/2023 3:10 PM, Shaun Kulesa wrote:
    The undefined variable $tid is what is confusing me.

    Notice Brian said the code was untested. I believe you
    will need this once in the main (also untested :)

    set tid [thread::create {thread::wait}]

    and then pass $tid into unzip_background

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rich@21:1/5 to Shaun Kulesa on Thu Apr 20 01:32:34 2023
    Shaun Kulesa <shaunkulesa@gmail.com> wrote:
    The undefined variable $tid is what is confusing me.

    That should be the thread id of the background thread that will execute
    the function.

    That was one of thosee "untested" (meaning: "might contain bugs") items
    to which the author referred.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ralf Fassel@21:1/5 to All on Thu Apr 20 11:09:49 2023
    * Shaun Kulesa <shaunkulesa@gmail.com>
    | When I said - "It works now, I should take breaks when coding, I must
    | have done something silly which caused an error.", that was when I
    | just tested it in the global code execution area. If I have it in my
    | namespace it won't find the variable.

    | When I put $download_return on that last line, it won't find the
    | variable, this only happens when I have it in a namespace.

    This is because 'vwait' refers to variables in the global namespace by
    default, and obviously (though not explicitely documented) thread::send
    does the same.

    So in order to use that variable inside a proc, you also need to refer
    to it either by fully-qualified access

    puts $::download_return

    or by

    global download_return;
    puts $download_return

    HTH
    R'

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Thu Apr 20 06:13:33 2023
    When I tried unzipping a large zip file it made the program not respond, I must of done something wrong.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Thu Apr 20 05:16:08 2023
    I've just finished the code, I've never used lambda in tcl before so I had a go at learning it which I needed to fix the code.

    proc install {version location} {
    set status_list_box [listbox .install_frame.status_list_box -width 80 -height 10]
    grid $status_list_box -row 2 -column 0 -columnspan 2 -sticky news

    set tid [thread::create {thread::wait}]

    install_background $location $version $status_list_box $tid
    }

    proc install_background {location version status_list_box mainid} {
    thread::send $mainid -async [apply {{location version status_list_box mainid} {
    package require zipfile::decode

    proc download {location version status_list_box mainid} {
    thread::send $mainid -async [$status_list_box insert end "Downloading Tcl $version in $location"]

    set f [open "$location\\Tcl.zip" wb]
    set tok [http::geturl $version -channel $f -binary 1]
    close $f

    if {[http::status $tok] eq "ok" && [http::ncode $tok] == 200} {
    thread::send $mainid -async [$status_list_box insert end "Downloaded successfully"]
    } else {
    thread::send $mainid -async [$status_list_box insert end "Download failed"]
    return
    }

    http::cleanup $tok

    unzip $location $version $status_list_box $mainid
    }

    proc unzip {location version status_list_box mainid} {
    $status_list_box insert end "Installing Tcl $version in $location"

    thread::send $mainid -async [$status_list_box insert end "Extracting files to $location"]

    ::zipfile::decode::open $location\\Tcl.zip
    set archiveDict [::zipfile::decode::archive]
    ::zipfile::decode::unzip $archiveDict $location
    ::zipfile::decode::close

    thread::send $mainid -async [$status_list_box insert end "Installed successfully"]
    }

    download $location $version $status_list_box $mainid

    }} $location $version $status_list_box [thread::id]]
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to Shaun Kulesa on Thu Apr 20 07:14:10 2023
    On Thursday, April 20, 2023 at 6:13:36 AM UTC-7, Shaun Kulesa wrote:
    When I tried unzipping a large zip file it made the program not respond, I must of done something wrong.

    In several places there is the pattern:

    thread::send $mainid -async [ some command ]

    The [] brackets evaluate the "some command" first, then pass the result to thread::send.
    The script argument to thread::send needs to be quoted differently. My original example was missing the appropriate quoting, so my bad.
    Something like this should work:

    thread::send $mainid -async [ list some command ]

    -Brian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Thu Apr 20 07:27:06 2023
    If I make the command and arguments a list:
    thread::send $mainid -async [list $status_list_box insert end "Downloaded successfully"]

    It will not insert the message into the list box.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From briang@21:1/5 to Shaun Kulesa on Thu Apr 20 09:17:52 2023
    On Thursday, April 20, 2023 at 7:27:09 AM UTC-7, Shaun Kulesa wrote:
    If I make the command and arguments a list:
    thread::send $mainid -async [list $status_list_box insert end "Downloaded successfully"]

    It will not insert the message into the list box.

    There are likely more errors in the code, and the error is not being reported. I noticed that the -async option is supposed to be before the thread id:

    thread:send -async $mainid ....

    -Brian

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Shaun Kulesa on Thu Apr 20 09:50:46 2023
    On 4/20/2023 7:27 AM, Shaun Kulesa wrote:
    If I make the command and arguments a list:
    thread::send $mainid -async [list $status_list_box insert end "Downloaded successfully"]

    It will not insert the message into the list box.

    I believe the -async is misplaced as Brian said.

    A quick glance at your new code also seems to be sending in $tid (the worker thread) into the parameter mainid (the main thread id) when you call install_background from within install.

    You have to deal with 2 thread id's, the worker thread you create, and the mainthread's id which you get via [thread::id] - executed in the main program. All thread abled'd programs begin inside the main thread. That's where the gui lives, so only the
    main thread can update the list boxes.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Thu Apr 20 10:57:19 2023
    I'm having an issue where the thread is package requiring http 1.0 whereas my main gui thread is requiring version 2.9.8 which is the version I want.

    This is the auto path for my gui thread:
    D:/Tcl/lib/tcl8.6 D:/Tcl/lib D:/Tcl/lib/cawt2.9.2 D:/Tcl/lib/tcl3d0.9.5 D:/Tcl/lib/tcllib1.21 D:/Tcl/lib/vfs1.4.2/template D:/Tcl/lib/tk8.6 D:/Tcl/lib/tk8.6/ttk

    This is the auto path for my threaded code:
    D:/Tcl/lib/tcl8.6 D:/Tcl/lib D:/Tcl/lib/cawt2.9.2 D:/Tcl/lib/tcl3d0.9.5 D:/Tcl/lib/tcllib1.21 D:/Tcl/lib/vfs1.4.2/template

    The paths are identical, for extra information I am using Pauls batteries included version and I have not added any extra dependencies.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Shaun Kulesa@21:1/5 to All on Thu Apr 20 11:17:38 2023
    I fixed it by putting the version number on the end:

    package require http 2.9.8

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From et99@21:1/5 to Shaun Kulesa on Thu Apr 20 12:19:42 2023
    On 4/20/2023 11:17 AM, Shaun Kulesa wrote:
    I fixed it by putting the version number on the end:

    package require http 2.9.8
    I'm not familiar with the distro you are using (bawt) but I do know that a new thread does not always have everything the main thread has. For example, when I use the magicsplat distro, and I want to use Tk in a thread, even though I startup with wish,
    the thread has to do a [package require Tk].

    I also have used the nightly single file builds for 8.7 and there I found a big difference between auto_path in the threads and the main thread. I had to send in code to setup the auto_path there.

    Also, when a thread get's an error (on windows, not sure about linux) it is usually silent and the thread exits. You can use thread::exists to see if something had gone wrong, but you'll need to do more to know what caused it.

    BTW, you might want to make tid a global, since otherwise, that variable will go away when the proc install returns. I normally create my threads outside of procs, where vars are global by default.

    I built a thread package of my own where I not only load Tk, but I surround all my thread::create scripts with a catch, and then present a tk dialog box, otherwise my errors in thread::create went unreported - unlike with thread::send where errors are
    sent back from a malformed script to the creating thread. And from windows, you can't do a puts (to stdout or stderr) from a thread, and have to do a thread::send back to the main for that.

    Also, note that on linux, if you do want to use Tk inside a thread, you need at least 8.6.12 (iirc) which fixed the linux Tk in multiple threads bug.

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