Tcl package Thread source code

Ticket Change Details
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2018 Conference, Houston/TX, US, Oct 15-19
Send your abstracts to tclconference@googlegroups.com
or submit via the online form by Aug 20.
Overview

Artifact ID: a9b4e19a36f9b7a938549de45776b33dac4cadc0bf99763924f2d02879a6d4bf
Ticket: b5709ea9060d17f58ba48110351c964b3408e362
[::thread::send -async] posting order not respected when sending to current thread
User & Date: adrianmedranocalvo 2018-07-31 11:27:59
Changes

  1. Change assignee to "nobody"
  2. Change closer to "nobody"
  3. Change cmimetype to "text/plain"
  4. Change comment to:

    if {0} { When the target thread of [::thread::send -async] is the current thread, the async script is not evaluated in order with respect to other [::thread::send -async] scripts.

    Let's call a [::thread::send -async] invoked from the current thread and directed to the current thread a local [::thread::send -async], and a [::thread::send -async] invoked from any other thread and directed to the former thread a remote [::thread::send -async].

    Current behaviour is that all remote [::thread::send -async] scripts will be evaluated before any local [::thread::send -asinc] scripts are, even in the case where the local scripts have been posted before the remote ones. See the script below for a concise example.

    Intuitively, [::thread::send -async] scripts should be queued and evaluated in the order they were added to the queue (that is, except if the -head argument was given).

    The script below demostrates this issue. We append to a global variable in the main thread in four different ways, in order: - An after 0 script - An after idle script - A local [thread::send -async] - A remote [thread::send -async] - Another after 0 script - Another after idle script

    The printed trace of the script is reproduced below. Contrary to the posting order, the remote [thread::send -async] is evaluated before the local [thread::send -async].

    ~~~ REMOTE-THREAD-SEND AFTER0-BEG AFTER0-END IDLE-BEG LOCAL-THREAD-SEND IDLE-END ~~~

    Without knowing the details of the Thread package, one would expect the local and remote [thread::send -async] to be evaluated in the order they were posted. Instead, the remote [thread::send -async] are invariably evaluated before the local ones; and the local ones are evaluated as [after idle] commands.

    The cause for this behaviour is an optimization in threadCmd.c, commented as "Short circuit sends to ourself", where local [thread::send -async] are converted to [after idle], implying that a different queue is used for local [thread::send -async] events as oposed to remote [thread::send -async] events.

    How important is this optimization? I can't see much performance being lost if we would disable the optimization and would let local [::thread::send -async] be added to the queue along with all others. The benefit from this change would be a more consistent behaviour.

    The underlying use-case is a server with connection-specific threads. The connection-specific thread uses local [thread::send -async] in order to delay the flushing of responses, so that the application's locks are grabbed for a minimum amount of time. Other threads use remote [thread::send -async] to the connection thread in order to send messages through the connection. The optimization above difficults ensuring the order the responses are flushed.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ }

    package require Thread;

    set t(main) [::thread::id] set t(other) [::thread::create]

    # Let t(other) know the main thread's id, t(main). ::thread::send $t(other) [list array set t [array get t]]

    after 0 {lappend ::trace AFTER0-BEG;} after idle {lappend ::trace IDLE-BEG;}

    ::thread::send -async $t(main) { lappend ::trace LOCAL-THREAD-SEND; } ::thread::send $t(other) { ::thread::send -async $t(main) { lappend ::trace REMOTE-THREAD-SEND; } }

    after 0 {lappend ::trace AFTER0-END;} after idle {lappend ::trace IDLE-END;}

    after 100 {set forever now}; vwait forever; puts [join $::trace "\n"];

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  5. Change foundin to "2.8.0"
  6. Change is_private to "0"
  7. Change login to "adrianmedranocalvo"
  8. Change priority to "5 Medium"
  9. Change private_contact to "219192cc5b7de6cef9c96726d1feb29d0382f2dc"
  10. Change resolution to "None"
  11. Change severity to "Important"
  12. Change status to "Open"
  13. Change submitter to "adrianmedranocalvo"
  14. Change subsystem to "80. Thread Package"
  15. Change title to:

    [::thread::send -async] posting order not respected when sending to current thread

  16. Change type to "Bug"