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

Igor Stasenko siguctua at gmail.com
Tue May 5 17:01:06 UTC 2009


2009/5/5 Andreas Raab <andreas.raab at gmx.de>:
> 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
>

the fundamental difference that by adding the protocol
(waitForSignalBy:/waitComplete:) i can put any waiter to the
semaphore, instead of just process.
This means, that i can schedule a waiting for a signal from
semaphore/delay without stopping any process.
If this doesn't have any potential use cases, then let just abandon
this idea alltogether.

> 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.
>

Surely, this is an optimization. But in my current implementation
(which is not yet released due the questions above) , a Delay holds a
reference to Process, not Semaphore. So comparing to old scheduler:
a 'Delay waitForMilliseconds:  xxx '

will create 1 object (Delay) instead of two (Delay + Semaphore).

Which IMO is more optimal :)

And new DelayWaitTimeout will have same references - semaphore +
process, so there will be no difference , except that it adds
'semaphore' ivar instead of 'process' ivar.
So, everythign is same for this case, except that initially, a new
Delay don't needs to create a Semaphore instance.

> 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.
>>
>>
>
>
>



-- 
Best regards,
Igor Stasenko AKA sig.



More information about the Squeak-dev mailing list