Tcl package Thread source code

Ticket Change Details
Login
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. assignee changed to: "nobody"
  2. closer changed to: "nobody"
  3. cmimetype changed to: "text/plain"
  4. comment changed 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. foundin changed to: "2.8.0"
  6. is_private changed to: "0"
  7. login: "adrianmedranocalvo"
  8. priority changed to: "5 Medium"
  9. private_contact changed to: "219192cc5b7de6cef9c96726d1feb29d0382f2dc"
  10. resolution changed to: "None"
  11. severity changed to: "Important"
  12. status changed to: "Open"
  13. submitter changed to: "adrianmedranocalvo"
  14. subsystem changed to: "80. Thread Package"
  15. title changed to:
    [::thread::send -async] posting order not respected when sending to current thread
    
  16. type changed to: "Bug"