[squeak-dev] Re: Interaction between objects which can be waited on, and their clients(waiters)

Andreas Raab andreas.raab at gmx.de
Tue May 5 15:44:59 UTC 2009


Hi Igor -

How is what you are proposing fundamentally different from a solution 
that simply creates a watcher process for each event source and then 
combines those properly? I.e.,

Object subclass: #MultiWait
   instanceVariableNames: 'eventSemas'
   ...

waitForAll
   "waits for signals from all event sources"
   eventSemas do:[:sema| sema wait].

waitForOne
   "Waits for signals from at least one event source.
    Returns all the semaphores that have been signaled."
   waitSema := Semaphore new.
   processes := eventSemas do:[:sema| [sema wait. waitSema signal] fork].
   waitSema wait. "or waitTimeoutMSecs:"
   signaled := Set new.
   eventSemas with: processes do:[:list :proc|
     (proc suspend == list) ifTrue:[signaled add: list].
     proc terminate.
   ].
   ^signaled

DelayWaitTimeout is an optimization that avoids the need for additional 
processes - when you use #waitTimeoutMSecs: a *lot* (say, because you're 
running a server with heavy network activity) the additional overhead 
incurred by the additional processes (and process switches) gets 
relevant in a hurry. But other than that, the above is a straightforward 
solution that will work with anything that supports the #wait protocol.

Cheers,
   - Andreas

Igor Stasenko wrote:
> Hello list,
> 
> I stared @ DelayWaitTimeout class, and thinking, how to implement it
> in new scheduler..
> First i thought , just make it quickly and forget about it, but one
> thing which don't makes me feel good about it, that
> DelayWaitTimeout is a perfect example, when you need to stop a Process
> until one of the multiple events occurs - in case of DelayWaitTimeout
> its either semaphore signaled or delay expired.
> 
> So, i thinking, what if instead of implementing a DelayWaitTimeout ,
> which works only for 2 objects - delay & semaphore, implement a more
> generic class , which would allow us to wait for any number of objects
> and blocks process until one of them is signaled. Or, blocks process
> until all of them signaled.
> There's nothing new, in fact, in Windoze there an API function, called
> WaitForMultipleObjects, which does exactly what i describing - it
> could wait on multiple objects, releasing a waiter once a single
> object signaled, or release waiter only after all objects signaled.
> 
> Here is my thoughts, how to implement that.
> First, we need to allow Delay & Semaphore to work with abstract waiter
> object (not just Process).
> A proposed protocol between object which acts as one who can be waited
> on, and object who acts as waiter is following:
> 
> To start waiting, we sending a #waitForSignalBy: waiter
> semaphore waitForSignalBy: waiter
> or
> delay waitForSignalBy: waiter
> 
> then, default #wait could be implemented, in both cases, simply as:
> 
> ^ self waitForSignalBy: Processor activeProcess.
> 
> now, after issuing #waitForSignalBy: we have the following possible cases:
> - given object is already signaled (as a semaphore with excess
> signals), in this case we immediately sending #waitComplete: to waiter
> 
> - given object is scheduled for being signaled later , in this case we
> sending #startWaitingOn: to waiter.
> 
> - now after #startWaitingOn: issued and once a semaphore/delay
> signaled we sending #waitComplete: to waiter.
> 
> - in case if semaphore/delay abandoned, we sending #waitAbandoned: to
> waiter. This happens, for instance, when we terminating a process who
> currently waits on semaphore.
> 
> (If you have a better idea how to name these messages, please make a guess)
> 
> Now, by having such protocol implemented for Delay, Semaphore &
> Process, we now can easily introduce another class which could allow
> us to wait for multiple events.
> 
> Again, i'm not sure how properly call it..
> Just want to illustrate the usage:
> 
> semaphore := Semaphore new.
> delay := Delay forMilliseconds: 100.
> 
> signaler := (MultipleWait on: { semaphore. delay }) waitForOne.  "wait
> until one of the listed objects get signaled"
> or:
> result := (MultipleWait on: { semaphore. delay }) waitForAll. "wait
> until all of the listed objects get signaled"
> 
> by default, MultipleWait>>waitForSignalBy: is releasing waiter once
> one of the listed objects signaled (as in waitForOne case).
> Not sure about return result of #waitForAll, IMO , it could be just a
> boolean value - return true, if all objects signaled, or false in case
> if waiting abandoned.
> 
> Now, of course, since  MultipleWait acts as a waiter and as an object
> who can be waited on, we can allow nesting:
> 
> mwait1 := MultipleWait on: { sema1. sema2 }.
> (MultipleWait on: { mwait1. delay }) waitForOne.
> 
> and finally, as you may guess , a Semaphore>>waitTimeoutMSecs: now can
> be implemented as:
> 
> waitTimeoutMSecs: anInteger
> 	"Wait on this semaphore for up to the given number of milliseconds,
> then timeout.
> 	Return true if the deadline expired, false otherwise."
> 	| delay |
> 
>        delay := Delay forMilliseconds: (anInteger max: 0).
>        ^ delay == (MultipleWait on: { self. delay }) waitForOne.
> 
> 




More information about the Squeak-dev mailing list