This posting was meant to define the documentation for the new Rexx classes 
EventSemaphore and
MutexSemaphore.

Just wanted to make sure that it does not get lost, hence the question whether 
I should submit it as
some form of a patch?

Also, if I know into which XML-file to place it, I could try to study the 
existing documentation of
the classes and the used tags and attributes there and supply also a XML 
rendering that I would
think would be appropriate. So please advise.

---rony


On 14.03.2019 20:05, Rony G. Flatscher wrote:
> On 14.03.2019 18:10, Rick McGuire wrote:
>> A couple of notes that need to added to the MutexSemaphore section
>>
>> 1) On a single thread, acquire requests nests, so if a thread calls acquire 
>> again while already
>> having obtained the semaphore, it will be not blocked. It requires an 
>> equivalent number of
>> release calls to free up the mutex. 
>>
>> 2) If the thread holding the mutex ends without releasing the semaphore, the 
>> semaphore will be
>> released automatically.
>>
>> Rick 
>
> Thanks, this version now includes this information in the "acquire" part:
>
>     
> ===============================================================================
>     5.4.x EventSemaphore Class
>
>     Semaphores get used in multithreaded scenarios.
>
>     An "event semaphore" allows one thread "A" to synchronize multiple threads
>     (like "B", "C", ...) with whom the event semaphore gets shared.  Thread
>     "A" creates the event semaphore and sends it the "reset" message.  Then
>     thread "A" supplies the event semaphore to the threads "B", "C", ..., each
>     of which sends the received event semaphore a "wait" message.  This will
>     block the threads "B", "C", ..., until thread "A" sends the "post" message
>     to the event semaphore.  At this time all threads waiting on the event
>     semaphore get released and can run in parallel on their threads.
>
>     5.4.x.1 close
>
>     >>--- close ---><
>
>     Closes the event semaphore.
>
>
>     5.4.x.2 isPosted
>
>     >>--- isPosted ---><
>
>     Returns .true if the event semaphore is in the "posted" state, such that
>     sending the "wait" message to this event semaphore would return
>     immediately.  A return value of .false indicates that the event semaphore
>     is not in the "posted" state, such that a "wait" message will block.
>
>
>     5.4.x.3 post
>
>     >>--- post ---><
>
>     Sets the event semaphore to the "posted" state, signalling that the event
>     that other threads are waiting on has occurred, such that all threads
>     waiting on this event semaphore will be released and start to run again.
>
>
>     5.4.x.4 reset
>
>     >>--- reset ---><
>
>     Resets (clears) the event semaphore to the non-"posted" state, such that 
> "wait"
>     messages to this event semaphore will block.
>
>
>     5.4.x.5 uninit
>
>     >>--- uninit ---><
>
>     This method cleans up the object when it is garbage collected.  It should
>     not be invoked directly except via an uninit method of a subclass of the
>     EventSemaphore class.
>
>
>     5.4.x.6 wait
>
>     >>--- wait(--+-------------+--)---><
>                  |             |
>                  +-- timeout --+
>
>     Waits (blocks) on the event semaphore until it gets "posted".  If the
>     optional argument "timeout" was supplied it must be a whole number that
>     represents the milliseconds to wait on the event semaphore before
>     returning.
>
>
>     If no "timeout" value was supplied or its value is negative, the wait will
>     be forever, ie. until the event semaphore gets "posted".
>
>     If the "timeout" value is zero the method returns immediately with the
>     same value that the method "isPosted" would return if sent to the event
>     semaphore instead.
>
>     The method returns .true if the event semaphore got "posted", .false if
>     the method returns prematurely because the given timeout has occurred.
>
>
>     Example 5.xxx
>
>     The following example will fetch the routine object "WORKER" and in a loop
>     will send the routine object the message "start" (defined in the ooRexx
>     root class "Object") supplying the message name ("call") to be sent on a
>     new (asynchroneous) thread, and as arguments the event semaphore to wait
>     on and the number of the loop for the respective asynchroneous message.
>
>     The main program creates an event semaphore and sends the message "reset"
>     to it.  Then it sends the "start" message three times to the routine
>     object in the loop, causing the routine "worker" to run on three different
>     threads, where in each thread the executed routine then waits on the event
>     semaphore ("wait" message to the event semaphore).  The main program then
>     sleeps for five seconds, before sending the "post" message to the event
>     semaphore, which will awake the routines on the three threads, ie.  they
>     return from the wait message and execute on their threads in parallel,
>     causing each to sleep for two seconds before returning from the routine
>     invocation.
>
>     <code>
>             eventSem=.eventSemaphore~new  -- create an event semaphore, will 
> be in posted state
>             dt=.dateTime~new     -- a .DateTime object to allow measuring 
> elapsed time
>             say "/main\     "  pp(dt~elapsed) "currently 
> 'eventSem~isPosted':" pp(eventSem~isPosted)
>             eventSem~reset       -- reset event semaphore, such that "wait" 
> will block
>             say "/main\     "  pp(dt~elapsed) "after 'eventSem~reset', 
> 'eventSem~isPosted':" pp(eventSem~isPosted)
>
>             w=.routines~waiter   -- get routine 'WAITER' as a routine object
>             do i=1 to 3
>                say "/main\     "  pp(dt~elapsed)   "running routine 'WAITER' 
> #" pp(i) "asynchroneously"
>                w~start("call", eventSem, i)  -- call (run) the routine object 
> on a separate thread
>             end
>             say
>
>             sleepTime=5
>             say "/main\     "  pp(dt~elapsed)  "sleeping" pp(sleepTime) 
> "seconds ..."
>             call sysSleep sleepTime -- sleep
>
>             say "/main\     "  pp(dt~elapsed)  "awoke, about doing an 
> 'eventSem~post' ..."
>             say
>             eventSem~post        -- wake up all threads waiting on this event 
> semaphore
>             say "\main/     "  pp(dt~elapsed)  "--> leaving main, other 
> threads may still be active!"
>
>             ::routine waiter     -- this routine will be called on a separate 
> thread
>                use arg eventSem, nr
>                s=.dateTime~new   -- we use our own .DateTime object to 
> measure elapsed time on this thread
>                say .context~name" #" nr":" pp(s~elapsed) "arrived, 
> 'eventSem~isPosted'="pp(eventSem~isPosted)", about: 'eventSem~wait'"
>                eventSem~wait     -- wait until main program posts this event 
> semaphore
>                say .context~name" #" nr":" pp(s~elapsed) "wait over, 
> 'eventSem~isPosted':" pp(eventSem~isPosted)
>
>                sleepTime=2
>                say .context~name" #" nr":" pp(s~elapsed) "now sleeping" 
> pp(sleepTime) "second(s)"
>                call syssleep sleeptime -- sleep
>                say .context~name" #" nr":" pp(s~elapsed) "sleep over"
>
>             ::routine pp         -- "pretty print" ;) (encloses argument in 
> square brackets)
>               return "["arg(1)"]"
>     </code>
>
>     Running this program may yield the following output:
>
>     <code>
>             /main\      [00:00:00.000000] currently 'eventSem~isPosted': [1]
>             /main\      [00:00:00.000000] after 'eventSem~reset', 
> 'eventSem~isPosted': [0]
>             /main\      [00:00:00.015000] running routine 'WAITER' # [1] 
> asynchroneously
>             /main\      [00:00:00.015000] running routine 'WAITER' # [2] 
> asynchroneously
>             WAITER # 1: [00:00:00.000000] arrived, 'eventSem~isPosted'=[0], 
> about: 'eventSem~wait'
>             /main\      [00:00:00.015000] running routine 'WAITER' # [3] 
> asynchroneously
>             WAITER # 2: [00:00:00.000000] arrived, 'eventSem~isPosted'=[0], 
> about: 'eventSem~wait'
>
>             WAITER # 3: [00:00:00.000000] arrived, 'eventSem~isPosted'=[0], 
> about: 'eventSem~wait'
>             /main\      [00:00:00.031000] sleeping [5] seconds ...
>             /main\      [00:00:05.056000] awoke, about doing an 
> 'eventSem~post' ...
>
>             \main/      [00:00:05.056000] --> leaving main, other threads may 
> still be active!
>             WAITER # 2: [00:00:05.041000] wait over, 'eventSem~isPosted': [1]
>             WAITER # 1: [00:00:05.041000] wait over, 'eventSem~isPosted': [1]
>             WAITER # 3: [00:00:05.025000] wait over, 'eventSem~isPosted': [1]
>             WAITER # 2: [00:00:05.057000] now sleeping [2] second(s)
>             WAITER # 1: [00:00:05.057000] now sleeping [2] second(s)
>             WAITER # 3: [00:00:05.041000] now sleeping [2] second(s)
>             WAITER # 3: [00:00:07.069000] sleep over
>             WAITER # 2: [00:00:07.085000] sleep over
>             WAITER # 1: [00:00:07.085000] sleep over
>     </code>
>
>
>
>
>
>
>     
> ===============================================================================
>
>     5.4.x MutexSemaphore Class
>
>     Semaphores get used in multithreaded scenarios.
>
>     A "mutex semaphore" allows a thread "A" to "acquire" it exclusively,
>     causing any other thread that sends the message "acquire" to the same
>     mutex semaphore to be blocked as long as thread "A" does not "release" the
>     mutex semaphore.
>
>     The first thread "A" that acquired the mutex semaphore is the one that
>     holds it exclusively and is able to execute, all other threads "B", "C",
>     ..., that tried to "acquire" the same mutex semaphore exclusively
>     afterwards get blocked.  Once thread "A" releases the mutex semaphore one
>     of the other blocked threads "B", "C", ...  becomes able to execute, while
>     the other threads remain blocked.  Then, when the executing thread
>     releases the mutex semaphore the next blocked thread gets released and
>     will be able to continue running, etc.
>
>     Note: there is no predefined sequence that determines which of the blocked
>     threads will get scheduled to run next once the mutex semaphore received
>     the "release" message as this scheduling is done by the operating system.
>
>
>     5.4.x.1 acquire
>
>     >>--- acquire(--+-------------+--)---><
>                     |             |
>                     +-- timeout --+
>
>     Acquires the mutex semaphore exclusively and blocks any other threads that
>     also attempt to "acquire" the mutex semaphore until the mutex semaphore
>     gets the message "release" sent.
>
>     If the optional argument "timeout" was supplied it must be a whole number
>     that represents the milliseconds to wait on the mutex semaphore before
>     returning.
>
>     If no "timeout" value was supplied or its value is negative, the blocking
>     will be forever, ie.  until the mutex semaphore becomes available as the
>     result of another thread releasing it.
>
>     If the "timeout" value is zero the method returns immediately.  The method
>     returns .true if the mutex semaphore got acquired exclusively, .false else
>     (some other thread holds the mutex semaphore).  This can be used to try to
>     acquire a mutex semaphore without being blocked, if currently it is
>     already exclusively acquired by another thread.
>
>     The method returns .true if the mutex semaphore got acquired, .false if
>     the method returns prematurely because the given timeout has occurred.
>
>     Note 1: a thread that has successfully acquired a mutex semaphore may send
>     additional "acquire" messages without blocking.  It requires an equivalent
>     number of "release" messages to free up the mutex semaphore.
>
>     Note 2: if the thread that has successfully acquired the mutex semaphore 
>     ends without releasing it, the semaphore will be released automatically.  
>
>
>     5.4.x.2 close
>
>     >>--- close ---><
>
>     Closes the mutex semaphore.
>
>
>     5.4.x.3 release
>
>     >>--- release ---><
>
>     Releases (clears) the mutex semaphore, such that one of the blocked 
> threads
>     becomes able to "acquire" it successfully.
>
>
>     5.4.x.4 uninit
>
>     >>--- uninit ---><
>
>     This method cleans up the object when it is garbage collected.  It should
>     not be invoked directly except via an uninit method of a subclass of the
>     MutexSemaphore class.
>
>
>
>     Example 5.xxx
>
>     In the following example the main program will create a mutex semaphore
>     and acquire it for itself, such that any other thread that tries to
>     acquire the same mutex semaphore gets blocked.  The main program then
>     fetches the routine object "WORKER" and in a loop will send the routine
>     object the message "start" (defined in the ooRexx root class "Object")
>     supplying the message name ("call") to be sent on a new (asynchroneous)
>     thread, and as arguments the mutex semaphore that they need to acquire and
>     the number of the loop for the respective asynchroneous message.
>
>     The main program then sleeps for three seconds before releasing the mutex
>     semaphore, which allows one of the blocked threads to acquire it
>     successfully.  The routine on that thread will sleep for two seconds and
>     then return which causes its thread of execution to end (this will
>     automatically release the acquired mutex semaphore).  This in turn allows
>     another blocked thread to acquire the mutex semaphore and do the same
>     (sleep for two seconds and then return from the invocation ending its
>     thread of execution), which in turn allows the last blocked thread to
>     acquire the mutex semaphore and do the same.
>
>     The output will demonstrate that the three routine threads are blocked
>     until the main program releases the mutex semaphore.  Please note that the
>     sequence in which the blocked threads get scheduled to be run next is
>     dependent on the scheduling algorithms of the operating system.
>
>     <code>
>             mutexSem=.mutexSemaphore~new  -- create a mutex semaphore, will 
> be in released state
>             dt=.dateTime~new     -- a .DateTime object to allow measuring 
> elapsed time
>             mutexSem~acquire     -- we block everyone else
>             say "/main\     "  pp(dt~elapsed) "'mutexSem' created and 
> acquired"
>             w=.routines~waiter   -- get routine 'WAITER' as a routine object
>             do i=1 to 3
>                say "/main\     "  pp(dt~elapsed) "running routine 'WAITER' #" 
> pp(i) "asynchroneously"
>                w~start("call", mutexSem, i)  -- call (run) the routine object 
> on a separate thread
>             end
>             say
>             sleepTime=3
>             say "/main\     "  pp(dt~elapsed) "sleeping" pp(sleepTime) 
> "seconds" "--> "~copies(5)
>             call sysSleep sleepTime -- sleep
>             say "/main\     "  pp(dt~elapsed) "awoke, about doing a 
> 'mutexSem~release' <--"
>             mutexSem~release     -- now allow one of the 'worker' threads 
> waiting on the mutexSem to run
>
>             sleepTime=7
>             say "/main\     "  pp(dt~elapsed) "sleeping" pp(sleepTime) 
> "seconds" "--> "~copies(5)
>             call sysSleep sleepTime -- sleep
>             say "\main/     "  pp(dt~elapsed) "awoke, leaving main" "<-- 
> "~copies(5)
>
>             ::routine waiter     -- this routine will be called on a separate 
> 'worker' thread
>                use arg mutexSem, nr
>                s=.dateTime~new   -- we use our own .DateTime object to 
> measure elapsed time on this thread
>                say .context~name" #" nr":" pp(s~elapsed) "arrived, about 
> doing 'mutexSem~acquire' ..."
>                mutexSem~acquire  -- wait until semaphore becomes 
> (exclusively) available to us
>                say .context~name" #" nr":" pp(s~elapsed) "after 
> 'mutexSem~acquire'"
>
>                sleepTime=2
>                say .context~name" #" nr":" pp(s~elapsed) "now sleeping" 
> pp(sleepTime) "second(s)"
>                call syssleep sleeptime -- sleep
>                say .context~name" #" nr":" pp(s~elapsed) "sleep over"
>                say
>
>             ::routine pp   -- "pretty print" ;) (encloses argument i square 
> brackets)
>               return "["arg(1)"]"
>     </code>
>
>     Running this program may yield the following output:
>
>     <code>
>             /main\      [00:00:00.000000] 'mutexSem' created and acquired
>             /main\      [00:00:00.000000] running routine 'WAITER' # [1] 
> asynchroneously
>             /main\      [00:00:00.000000] running routine 'WAITER' # [2] 
> asynchroneously
>             WAITER # 1: [00:00:00.000000] arrived, about doing 
> 'mutexSem~acquire' ...
>             /main\      [00:00:00.000000] running routine 'WAITER' # [3] 
> asynchroneously
>             WAITER # 2: [00:00:00.000000] arrived, about doing 
> 'mutexSem~acquire' ...
>
>             WAITER # 3: [00:00:00.000000] arrived, about doing 
> 'mutexSem~acquire' ...
>             /main\      [00:00:00.000000] sleeping [3] seconds --> --> --> 
> --> -->
>             /main\      [00:00:03.011000] awoke, about doing a 
> 'mutexSem~release' <--
>             /main\      [00:00:03.011000] sleeping [7] seconds --> --> --> 
> --> -->
>             WAITER # 1: [00:00:03.011000] after 'mutexSem~acquire'
>             WAITER # 1: [00:00:03.011000] now sleeping [2] second(s)
>             WAITER # 1: [00:00:05.023000] sleep over
>
>             WAITER # 2: [00:00:05.023000] after 'mutexSem~acquire'
>             WAITER # 2: [00:00:05.023000] now sleeping [2] second(s)
>             WAITER # 2: [00:00:07.036000] sleep over
>
>             WAITER # 3: [00:00:07.036000] after 'mutexSem~acquire'
>             WAITER # 3: [00:00:07.036000] now sleeping [2] second(s)
>             WAITER # 3: [00:00:09.048000] sleep over
>
>             \main/      [00:00:10.017000] awoke, leaving main <-- <-- <-- <-- 
> <--
>     </code>
>
>
>
>
>     
> ===============================================================================
>
> ---rony
>

_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to