Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I think I have two possible solutions. I am not particularly satisfied with either, but they do at least provide a reasonable alternative to the APM approach.</p> <p>The first does not meet your requirement of no blocking thread, but I think it is rather elegant because you can register callbacks and they will get called in round-robin fashion, but you still have the ability to call <code>Take</code> or <code>TryTake</code> as you normally would for a <code>BlockingCollection</code>. This code forces callbacks to be registered each time an item is requested. That is the signalling mechanism for the collection. The nice thing about this approach is that calls to <code>Take</code> do not get starved as they do in my second solution.</p> <pre><code>public class NotifyingBlockingCollection&lt;T&gt; : BlockingCollection&lt;T&gt; { private Thread m_Notifier; private BlockingCollection&lt;Action&lt;T&gt;&gt; m_Callbacks = new BlockingCollection&lt;Action&lt;T&gt;&gt;(); public NotifyingBlockingCollection() { m_Notifier = new Thread(Notify); m_Notifier.IsBackground = true; m_Notifier.Start(); } private void Notify() { while (true) { Action&lt;T&gt; callback = m_Callbacks.Take(); T item = Take(); callback.BeginInvoke(item, null, null); // Transfer to the thread pool. } } public void RegisterForTake(Action&lt;T&gt; callback) { m_Callbacks.Add(callback); } } </code></pre> <p>The second does meet your requirement of no blocking thread. Notice how it transfers the invocation of the callback to the thread pool. I did this because I am thinking that if it got executed synchronously then the locks would be held longer resulting in the bottlenecking of <code>Add</code> and <code>RegisterForTake</code>. I have looked it over closely and I do not think it can get live locked (both an item and a callback are available, but the callback never gets executed) but you might want to look it over yourself to verify. The only problem here is that a call to <code>Take</code> would get starved as callbacks always take priority.</p> <pre><code>public class NotifyingBlockingCollection&lt;T&gt; { private BlockingCollection&lt;T&gt; m_Items = new BlockingCollection&lt;T&gt;(); private Queue&lt;Action&lt;T&gt;&gt; m_Callbacks = new Queue&lt;Action&lt;T&gt;&gt;(); public NotifyingBlockingCollection() { } public void Add(T item) { lock (m_Callbacks) { if (m_Callbacks.Count &gt; 0) { Action&lt;T&gt; callback = m_Callbacks.Dequeue(); callback.BeginInvoke(item, null, null); // Transfer to the thread pool. } else { m_Items.Add(item); } } } public T Take() { return m_Items.Take(); } public void RegisterForTake(Action&lt;T&gt; callback) { lock (m_Callbacks) { T item; if (m_Items.TryTake(out item)) { callback.BeginInvoke(item, null, null); // Transfer to the thread pool. } else { m_Callbacks.Enqueue(callback); } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COThanks for the answer, but its slightly not what I'm looking for. This is what I'm currently doing, but with the APM pushed into the collection (the code you've provided). I guess the crux of my issue is that APM doesn't fit my requirements, its just the implementation I've used. My requirements demand a pattern which provides a solution to the question, "How can I signal a collection that I am ready for the next element, and have the collection execute a callback when that next element has arrived, without any threads being blocked?"
      singulars
    2. COI kind of figured that was not what you were after. It is an interesting problem though. Too bad `Add` is not `virtual` otherwise you might have been able to inject the notification there somehow. Maybe you could use one of the blocking queue implementations as a starting point. The problem is that you have to be careful how you deliver that notification otherwise another consumer will have grabbed the item first. I might play around with this today if I get time. Post an answer yourself if you figure it out. I don't know...you may find it easier to punt and just reference an another library.
      singulars
    3. COThe notification should contain the next element and should be controlled by the notifier. Perhaps the idea of this being a collection is erroneous; only via this mechanism can the next item be supplied, thus avoiding the issue of two observers contending over a single item. In other words, one observer can't use mechanism A to get the next item (i.e., `T Pop()`) while the other has registered for a callback.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload