Blocking collection

The blocking collection is a Delphi clone of .NET 4 BlockingCollection. It is a thread-safe collection that provides multiple simultaneous readers and writers. This implementation of blocking collection works only with the TOmniValue elements, which is not a big limitation provided that TOmniValue can store anything, including a class, an interface and a record.

See also demo 33_BlockingCollection.

IOmniBlockingCollection

The blocking collecting is exposed as an interface that lives in the OtlCollections unit.

IOmniBlockingCollection = interface
  ['{208EFA15-1F8F-4885-A509-B00191145D38}']
  function  GetContainerSubject: TOmniContainerSubject;
  //
  procedure Add(const value: TOmniValue);
  procedure CompleteAdding;
  function  GetEnumerator: IOmniValueEnumerator;
  function  IsCompleted: boolean;
  function  IsFinalized: boolean;
  function  Next: TOmniValue;
  procedure ReraiseExceptions(enable: boolean = true);
  procedure SetThrottling(highWatermark, lowWatermark: integer);
  function  Take(var value: TOmniValue): boolean;
  function  TryAdd(const value: TOmniValue): boolean;
  function  TryTake(var value: TOmniValue; 
    timeout_ms: cardinal = 0): boolean;
  property ContainerSubject: TOmniContainerSubject 
    read GetContainerSubject;
end;

There's also a class TOmniBlockingCollection which implements this interface. This class is public and can be used or reused in your code.

The blocking collection works in the following way:

- Add will add new value to the collection (which is internally implemented as a queue).

- CompleteAdding tells the collection that all data has been added. From now on, calling Add will raise an exception.

- TryAdd is the same as Add except that it doesn't raise an exception but returns False if the value can't be added (if CompleteAdding was already called)

- IsCompleted returns True after the CompleteAdding has been called.

- IsFinalized returns True if CompleteAdding has been called and the collection is empty.

- Next retrieves next element from the collection (by calling Take) and returns it as the result. If Take fails, an ECollectionCompleted exception is raised.

- ReraiseExceptions enables or disables internal exception-checking flag. Initially this flag is disabled. When the flag is enabled and Take or TryTake retrieve a TOmniValue holding an exception object, this exception is immediately raised.

- SetThrottling enables the throttling mechanism. See Throttling for more information.

- Take reads next value from the collection. If there's no data in the collection, Take will block until the next value is available. If, however, any other thread calls CompleteAdding while the Take is blocked, Take will unblock and return False.

- TryTake is the same as Take except that it has a timeout parameter specifying maximum time the call is allowed to wait for the next value. If INFINITE is passed in the timeout parameter, TryTake will block until the data is available or CompleteAdding is called.

- ContainerSubject property enables the blocking collection to partake in lock-free collection monitoring mechanism.

Enumerator calls Take in the MoveNext method and returns the value returned from Take. Enumerator will therefore block when there is no data in the collection. The usual way to stop the enumerator is to call CompleteAdding which will unblock all pending MoveNext calls and stop enumeration.

Throttling

Normally, a blocking collection can grow without limits and can fill up the available memory. If the algorithm doesn't prevent this intrinsically, it is sometimes useful to set up throttling, a mechanism which blocks additions when the blocking collection size reaches some predetermined value (high watermark) and which allows additions again when the size reaches another predetermined value (low watermark).

procedure SetThrottling(highWatermark, lowWatermark: integer);

The behaviour of Add, TryAdd, Take and TryTake is modified if the throttling is used.

When Add or TryAdd is called and number of elements in the blocking collection equals highWatermark, the code blocks. It will only continue if the number of elements in the collection falls below the lowWatermark or if the CompleteAdding is called.

When Take or TryTake take an element from the collection and adding is temporarily blocked because of the throttling and new number of elements in the collection is now below the lowWatermark, all waiting Add and TryAdd calls will be unblocked.

book/highlevel/blockingcollection.txt · Last modified: 2012/11/14 11:52 by gabr
Recent changes RSS feed Debian Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki