[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:13:42 UTC 2009


2009/5/5 Igor Stasenko <siguctua at gmail.com>:
> 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.
>

Similarily, if Semaphore implements a waiter protocol, then we don't
need to have a separate class (DelayWaitTimeout ),
we could simply do a nesting
Process --- waits on --> Semaphore --waits on--->Delay

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



-- 
Best regards,
Igor Stasenko AKA sig.



More information about the Squeak-dev mailing list