Instead of more classes for timeouts, here is what I came up with (still
need to test.) I still need to look at your other code. Cheers!
public bool AcquireAll(int millisecondsTimeout)
{
int slotsGot = 0;
int elapsedMS = 0;
DateTime start = DateTime.Now;
int timeout = millisecondsTimeout;
for (int i = 0; i < maxCount; i++)
{
try
{
if (! Acquire(timeout) )
{
// Could not acquire all slots, release any we may already have got.
if ( slotsGot > 0 )
Release(slotsGot);
return false;
}
else
{
elapsedMS = (int)((TimeSpan)(DateTime.Now - start)).TotalMilliseconds;
timeout = millisecondsTimeout - elapsedMS; // Next wait will be a
smaller timeout.
if ( timeout < 0 )
timeout = 0; // Next Acquire will return false if we have to wait;
slotsGot++; // If we get all remaining slots with no timeout, we just
keep going.
}
}
catch
{
// Catch any exception during Acquire wait.
if ( slotsGot > 0 )
Release(slotsGot);
throw;
}
} // end for.
// Count is not zero, so notify any/all starvation consumers.
lock(starvationLock) { Monitor.PulseAll(starvationLock); }
return true;
}
--
William Stacey, MVP
"TT (Tom Tempelaere)" <_|\|_0§P@|/\|titi____AThotmail.com|/\|@P§0_|\|_>
wrote in message news:R4fBc.161169$X61.8147071@phobos.telenet-ops.be...[color=blue]
> "TT (Tom Tempelaere)" <_N_0SPA|/\|titi____@hotmail.com|/\|APS0_N_> wrote[/color]
in[color=blue]
> message news:4wdBc.161048$aK1.8205361@phobos.telenet-ops.be...[color=green]
> > "William Stacey [MVP]" <staceywREMOVE@mvps.org> wrote in message
> > news:ODOd8ZlVEHA.1656@TK2MSFTNGP09.phx.gbl...[color=darkred]
> > > Here is the link. If you find an issue or think of a feature, please[/color][/color]
> post[color=green]
> > a[color=darkred]
> > > reply or send an email. Cheers!
> > >
http://www.mvptools.com/doco/csharp/...redjikstra.htm
> > > --
> > > William Stacey, MVP[/color][/color]
>
> [...][color=green]
> > Plus the millisecondsTimeout is deceiving, because the max time could be
> > ( maxSlots * millisecondsTimeout )
> > to acquire all slots.
> >
> > I noticed that there exists a
> > Release( int n )
> > method but not an
> > Acquire( int n )
> > method. Is this the intention?
> >
> > If you would write the Acquire( int n ) method, you could implement
> > Acquire() as Acquire( 1 )
> > and
> > AcquireAll() as Acquire( maxCount )[/color]
>
> Here's my try to implement Acquire( int nrSlots ). Warning: it doesn't[/color]
look[color=blue]
> very efficient though :D.
>
> public sealed class Semaphore
> {
> private int currentCount;
> private readonly int maxCount;
> private readonly object acquireLock = new object();
> private readonly object starvationLock = new object();
>
> public Semaphore( int currentCount, int maxCount )
> {
> Debug.Assert (
> maxCount >= 1 &&
> currentCount >= 0 &&
> currentCount <= maxCount
> );
> this.currentCount = currentCount;
> this.maxCount = maxCount;
> }
>
> public Semaphore( int maxCount )
> : this( maxCount, maxCount )
> {}
>
> public bool Acquire()
> {
> return _Acquire_N( 1, Timeout.Infinite );
> }
>
> public bool Acquire( int timeoutMs )
> {
> return _Acquire_N( 1, timeoutMs );
> }
>
> public bool AcquireAll()
> {
> return _Acquire_N( maxCount, Timeout.Infinite );
> }
>
> public bool AcquireAll( int overallTimeoutMs )
> {
> return _Acquire_N( maxCount, overallTimeoutMs );
> }
>
> public bool Acquire_N( int requestedCount )
> {
> return _Acquire_N( requestedCount, Timeout.Infinite );
> }
>
> public bool Acquire_N( int requestedCount, int overallTimeoutMs )
> {
> return _Acquire_N( requestedCount, overallTimeoutMs );
> }
>
> private bool _Acquire_N( int requestedCount, int overallTimeoutMs )
> {
> Debug.Assert (
> ( requestedCount > 0 ) &&
> ( overallTimeoutMs > 0 || ( overallTimeoutMs == Timeout.Infinite ) )
> );
>
> IAcquireTimeoutTracker acqTimeoutTracker = ( overallTimeoutMs > 0 ) ?
> (IAcquireTimeoutTracker) new RegularTimeoutTracker( overallTimeoutMs )[/color]
:[color=blue]
> new InfiniteTimeoutTracker();
> int acquiredCount = 0;
>
> lock( acquireLock )
> {
> while( acquiredCount != requestedCount )
> {
> while( currentCount == 0 )
> try
> {
> if( acqTimeoutTracker.HasElapsed ||
> !Monitor.Wait( acquireLock,[/color]
acqTimeoutTracker.RemainingWaitTime ) )[color=blue]
> {
> if( acquiredCount > 0 )
> Release( acquiredCount );
> return false;
> }
> }
> catch
> {
> if( acquiredCount > 0 )
> Release( acquiredCount );
> Monitor.Pulse( acquireLock );
> throw;
> }
>
> int targetCount = Math.Min( (requestedCount - acquiredCount),
> currentCount );
> acquiredCount += targetCount;
> currentCount -= targetCount;
>
> if( currentCount == 0 )
> lock( starvationLock )
> Monitor.PulseAll( starvationLock );
> }
> return true;
> }
> }
>
> internal interface IAcquireTimeoutTracker
> {
> bool HasElapsed {
> get;
> }
> int RemainingWaitTime {
> get;
> }
> }
> internal class InfiniteTimeoutTracker : IAcquireTimeoutTracker
> {
> public bool HasElapsed {
> get {
> return false;
> }
> }
> public int RemainingWaitTime {
> get {
> return Timeout.Infinite;
> }
> }
> }
> internal class RegularTimeoutTracker : IAcquireTimeoutTracker
> {
> DateTime deadline;
> TimeSpan timeout;
> public RegularTimeoutTracker( int timeoutMs )
> {
> deadline = DateTime.Now + TimeSpan.FromMilliseconds( timeoutMs );
> }
> public bool HasElapsed {
> get {
> return (timeout = deadline - DateTime.Now) <= TimeSpan.Zero;
> }
> }
> public int RemainingWaitTime {
> get {
> return timeout.Milliseconds;
> }
> }
> }
>
> public bool Release( int count )
> {
> // release implementation
> return true;
> }
>
> // ...
> }
>
> Cheers,
> ---
> Tom Tempelaere
>
>[/color]