Menu

#6 Semephore

open
control (5)
5
2003-04-24
2001-08-23
Evan Rempel
No

With packages that provide a call back mechanism, it is
possible to have many essentially background processes.
Take the http:: package. It is possible to have many
http::geturl requests running simultaneously, but there
is really no default way to coordinate the call backs for
the various open requests.

A semephore package with the ability to wait on any
number of call backs is desirable. Using a generic
waitany routine would require that I be aware of the
internal variables of the http package to wait on
changes of these variables. Implimenting all of this in
a single semephore package allows the same
functionality without the need to have knowledge of the
internals of a package.

As a staring point I submit the following. There may
have to be changes due to multi-threaded tcl code, but
its a start none the less.

# semephore.tcl
# Impementation of semephores
#
# Semephore::Signal token
# Semephore::Wait ?pattern? - returns token
# Semephore::Reset token

package provide SemephorePkg 2.1

# 2.1 - October 22, 2000
# - fixed a bug that would result in a very slow
memory leak

namespace eval Semephore {
variable SemData
array set SemData {}
variable SemAny 0

namespace export Signal Wait Reset
}

# -------------------------------------------------
Signal ----
# Signal a semephore
proc Semephore::Signal { SemToken } {
variable SemData
variable SemAny

if {![info exist SemData($SemToken)]} then {
set SemData($SemToken) 1
} else {
incr SemData($SemToken)
}
incr SemAny
}

# -------------------------------------------------
Wait ----
# Wait for a semephore
# Note: Resetting a semephore does not signal it.

proc Semephore::Wait { args } {
variable SemData
variable SemAny

set Pattern [lindex $args 0]
if {"$Pattern" == ""} then { set Pattern "*" }
set FoundFlag 0
set FoundName ""
if {$SemAny != 0} then {
foreach n [array names SemData $Pattern] {
if {$SemData($n) > 0} then {
set FoundName $n
set FoundFlag 1
break
}
}
}
while {!$FoundFlag} {
vwait Semephore::SemAny
foreach n [array names SemData $Pattern] {
if {$SemData($n) > 0} then {
set FoundName $n
set FoundFlag 1
break
}
}
}
if {[incr SemData($FoundName) -1] == 0} then {
unset SemData($FoundName)
}
incr SemAny -1
return $FoundName
}

# -------------------------------------------------
Reset ----
# Reset a semephore
# Note: Resetting a semephore does not signal it.

proc Semephore::Reset { SemToken } {
variable SemData
variable SemAny

if {[info exist SemData($SemToken)]} then {
incr SemAny -$SemData($SemToken)
}
set SemData($SemToken) 0
}

Discussion

  • Don Porter

    Don Porter - 2001-08-31
    • labels: --> control
    • assigned_to: nobody --> dgp
     
  • Andreas Kupries

    Andreas Kupries - 2001-09-11

    Logged In: YES
    user_id=75003

    I do not understand the part about the missing "default way
    of coordinating the callbacks".

    What do you mean by 'coordinating' ?

    Later you say 'ability to wait on any number of call backs
    is desirable'.

    If I undertand you correctly you want to start, say several
    http requests, and then perform an action after _all of
    them_ have reported back via the callback you gave them ?

    Can you give me an example script how to use this ?

    Note: It might have been better to attach the above
    implementation as a file instead of inlining it into the
    message itself. See the "check to upload and attach file"
    checkbox and entry items below, after the followups.

     
  • Don Porter

    Don Porter - 2001-09-12

    Logged In: YES
    user_id=80530

    I think there are many related ideas here. Tcl's variable
    and command traces, Tk's widget bindings, the Notifier
    class in [incr Tcl] that Michael McLennan described at
    the latest Tcl/Tk conference, as well as some internal
    code we use on the OOMMF project. I think this semaphore
    idea is similar too.

    They all have in common the notion of registering a callback
    script to be evaluated later when something happens. It
    would be a worthwhile exercise for someone to make an
    inventory of these techniques and what they share in common
    and how they differ. My impression is that the
    implementations are very different, even when the purposes
    are quite similar.

    Perhaps there's a fundamental capability to be extracted
    out and used by all?

     
  • Evan Rempel

    Evan Rempel - 2001-10-01

    Logged In: YES
    user_id=304001

    Sorry for the long delay.

    By "default way of coordinating callbacks", I mean that
    currently, if I am using two packages that have callback
    facilities, I must write my own code to wait on them at the
    same time. There is currently no mechanism in TCL to invoke
    asynchronous routines and wait for the one that completes
    firsts. I must wait for one routine specifically, and then
    wait for the other routine. If I wait for the wrong one,
    the following processing timeline is the result.

    1. Start asynchronous routine A (completes in 5 seconds)
    2. Start asynchronous routine B (completes in 2 seconds)
    3. Wait for routine A to complete (5 second idle time)
    4. Process the result of A (2 seconds)
    5. Wait for routine B to complete (0 seconds idle time)
    6. Process the result of B (2 seconds)

    Total time = 5 sec idle + 4 sec processing = 9 seconds.

    I would like to do

    1. Start asynchronous routine A (completes in 5 seconds)
    2. Start asynchronous routine B (completes in 2 seconds)
    3. Wait for routine A or B to complete (2 second idle time)
    4. Process the result of B (2 seconds)
    5. Wait for routine A or B to complete (1 second idle time)
    6. Process the result of A (2 seconds)

    Total time = 2 idle + 2 process + 1 idle + 2 proc = 7 sec

    If A and B are from the same package, this is usually easy,
    provided that the author build a "wait any" function.
    If A and B are from different packages, I must invent some
    way to handle this -> semaphores.

    The general concept is that I want to be able to wait for
    any of the callbacks, without knowing which one will
    respond first, or possibly waiting for any one of a
    particular type of callback, again without knowing which
    one will respond first.

    An example is something like

    http::geturl $A ... -command Semaphore::signal
    http::geturl $b ... -command Semaphore::signal
    timer::set "120 seconds" -command Semaphore::signal

    for {set x 1} {$x <= 3} {incr x} {
    set completed [semaphore::wait *]
    switch -glob -- $completed {
    ::http* { ... }
    ::timer* { ... }
    default { error "Unknown completed semaphore
    $completed" }
    }
    }

    This way, we don't get stuck on waiting for a response from
    a web server response, and we can determine timeouts. I
    realize that the http::geturl has a timeout option,
    however, the order in which you wait for them to complete
    becomes critical. With thus structure there is no need to
    build timeouts into all routines such as ftp, email, http,
    database, socket listening etc., and one does not have to
    wait for specific events to finish resulting in the ability
    to continue processing as soon as the first one completes.

    The above code is very safe, but one could wait on
    semaphores of the format ::http::* or any other format.

     
  • Evan Rempel

    Evan Rempel - 2003-03-25

    Logged In: YES
    user_id=304001

    I have updated and released the semaphore package that
    handles semaphores accross interpreters, while maintaining
    the simple signal/wait structure when not using interpreters.
    Also, package that have been built with "signal" events do not
    have to be modified when used within a child interpreter and
    the parent can wait on the childs semaphores.

    This package can be found at
    http://web.uvic.ca/~erempel/tcl/Semaphore/Semaphore.html

     
  • Andreas Kupries

    Andreas Kupries - 2003-04-11
    • priority: 5 --> 8
     
  • Andreas Kupries

    Andreas Kupries - 2003-04-11

    Logged In: YES
    user_id=75003

    Raising the priority of the item because its inclusion in the
    upcoming release was proposed in the Tcllib-devel mailing list.

    Supporting or contrarian statements should be made on the
    referenced mailing list for public discussion.

     
  • Larry W. Virden

    Larry W. Virden - 2003-04-12

    Logged In: YES
    user_id=15949

    Semaphore , as a package name, concerns me as
    it can have more than one meaning. On POSIX based
    machines, there is a kernal based IPC data structure
    called a semaphore,

    Given that both uses of the term are common, what
    would be the best way to disambiguate the issue?

     
  • Don Porter

    Don Porter - 2003-04-24
    • priority: 8 --> 5
     
  • Don Porter

    Don Porter - 2003-04-24

    Logged In: YES
    user_id=80530

    did not review in time for tcllib 1.4

     
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.