Let's say I have a class that implements the IDisposable interface. Something like this:
MyClass uses some unmanaged resources, hence the Dispose() method from IDisposable releases those resources. MyClass should be used like this:
using ( MyClass myClass = new MyClass() ) {
myClass.DoSomething();
}
Now, I want to implement a method that calls DoSomething() asynchronously. I add a new method to MyClass:
Now, from the client side, MyClass should be used like this:
using ( MyClass myClass = new MyClass() ) {
myClass.AsyncDoSomething();
}
However, if I don't do anything else, this could fail as the object myClass might be disposed before DoSomething() is called (and throw an unexpected ObjectDisposedException). So, the call to the Dispose() method (either implicit or explicit) should be delayed until the asynchronous call to DoSomething() is done.
I think the code in the Dispose() method should be executed in a asynchronous way, and only once all asynchronous calls are resolved. I'd like to know which could be the best way to accomplish this.
Thanks.
NOTE: For the sake of simplicity, I haven't entered in the details of how Dispose() method is implemented. In real life I usually follow the Dispose pattern.
UPDATE: Thank you so much for your responses. I appreciate your effort. As chakrit has commented, I need that multiple calls to the async DoSomething can be made. Ideally, something like this should work fine:
using ( MyClass myClass = new MyClass() ) {
myClass.AsyncDoSomething();
myClass.AsyncDoSomething();
}
I'll study the counting semaphore, it seems what I'm looking for. It could also be a design problem. If I find it convenient, I will share with you some bits of the real case and what MyClass really does.
It looks like you're using the event-based async pattern (see here for more info about .NET async patterns) so what you'd typically have is an event on the class that fires when the async operation is completed named DoSomethingCompleted (note that AsyncDoSomething should really be called DoSomethingAsync to follow the pattern correctly). With this event exposed you could write:
var myClass = new MyClass();
myClass.DoSomethingCompleted += (sender, e) => myClass.Dispose();
myClass.DoSomethingAsync();
The other alternative is to use the IAsyncResult pattern, where you can pass a delegate that calls the dispose method to the AsyncCallback parameter (more info on this pattern is in the page above too). In this case you'd have BeginDoSomething and EndDoSomething methods instead of DoSomethingAsync, and would call it something like...
var myClass = new MyClass();
myClass.BeginDoSomething(
asyncResult => {
using (myClass)
{
myClass.EndDoSomething(asyncResult);
}
},
null);
But whichever way you do it, you need a way for the caller to be notified that the async operation has completed so it can dispose of the object at the correct time.
Since C#8.0 you can use IAsyncDisposable.
using System.Threading.Tasks;
public class ExampleAsyncDisposable : IAsyncDisposable
{
public async ValueTask DisposeAsync()
{
// await DisposeAllTheThingsAsync();
}
}
Here is the reference to the official Microsoft documentation.
Async methods usually have a callback allowing you to do do some action upon completition. If this is your case it would be something like this:
// The async method taks an on-completed callback delegate
myClass.AsyncDoSomething(delegate { myClass.Dispose(); });
An other way around this is an async wrapper:
ThreadPool.QueueUserWorkItem(delegate
{
using(myClass)
{
// The class doesn't know about async operations, a helper method does that
myClass.DoSomething();
}
});
I consider it unfortunate that Microsoft didn't require as part of the IDisposable contract that implementations should allow Dispose to be called from any threading context, since there's no sane way the creation of an object can force the continued existence of the threading context in which it was created. It's possible to design code so that the thread which creates an object will somehow watch for the object becoming obsolete and can Dispose at its convenience, and so that when the thread is no longer needed for anything else it will stick around until all appropriate objects have been Disposed, but I don't think there's a standard mechanism that doesn't require special behavior on the part of the thread creating the Dispose.
Your best bet is probably to have all the objects of interest created within a common thread (perhaps the UI thread), try to guarantee that the thread will stay around for the lifetime of the objects of interest, and use something like Control.BeginInvoke to request the objects' disposal. Provided that neither object creation nor cleanup will block for any length of time, that may be a good approach, but if either operation could block a different approach may be needed [perhaps open up a hidden dummy form with its own thread, so one can use Control.BeginInvoke there].
Alternatively, if you have control over the IDisposable implementations, design them so that they can safely be fired asynchronously. In many cases, that will "just work" provided nobody is trying to use the item when it is disposed, but that's hardly a given. In particular, with many types of IDisposable, there's a real danger that multiple object instances might both manipulate a common outside resource [e.g. an object may hold a List<> of created instances, add instances to that list when they are constructed, and remove instances on Dispose; if the list operations are not synchronized, an asynchronous Dispose could corrupt the list even if the object being disposed is not otherwise in use.
BTW, a useful pattern is for objects to allow asynchronous dispose while they are in use, with the expectation that such disposal will cause any operations in progress to throw an exception at the first convenient opportunity. Things like sockets work this way. It may not be possible for a read operation to be exit early without leaving its socket in a useless state, but if the socket's never going to be used anyway, there's no point for the read to keep waiting for data if another thread has determined that it should give up. IMHO, that's how all IDisposable objects should endeavor to behave, but I know of no document calling for such a general pattern.
I wouldn't alter the code somehow to allow for async disposes. Instead I would make sure when the call to AsyncDoSomething is made, it will have a copy of all the data it needs to execute. That method should be responsible for cleaning up all if its resources.
You could add a callback mechanism and pass a cleanup function as a callback.
var x = new MyClass();
Action cleanup = () => x.Dispose();
x.DoSomethingAsync(/*and then*/cleanup);
but this would pose problem if you want to run multiple async calls off the same object instance.
One way would be to implement a simple counting semaphore with the Semaphore class to count the number of running async jobs.
Add the counter to MyClass and on every AsyncWhatever calls increment the counter, on exits decerement it. When the semaphore is 0, then the class is ready to be disposed.
var x = new MyClass();
x.DoSomethingAsync();
x.DoSomethingAsync2();
while (x.RunningJobsCount > 0)
Thread.CurrentThread.Sleep(500);
x.Dispose();
But I doubt that would be the ideal way. I smell a design problem. Maybe a re-thought of MyClass designs could avoid this?
Could you share some bit of MyClass implementation? What it's supposed to do?
Here's a more modern spin on this old question.
The real objective is to track the async Tasks and wait until they finish...
public class MyExample : IDisposable
{
private List<Task> tasks = new List<Task>();
public async Task DoSomething()
{
// Track your async Tasks
tasks.Add(DoSomethingElseAsync());
tasks.Add(DoSomethingElseAsync());
tasks.Add(DoSomethingElseAsync());
}
public async Task DoSomethingElseAsync()
{
// TODO: something else
}
public void Dispose()
{
// Block until Tasks finish
Task.WhenAll(tasks);
// NOTE: C# allows DisposeAsync()
// Use non-blocking "await Task.WhenAll(tasks)"
}
}
Consider turning it into a base class for re-usability.
And sometimes I use a similar pattern for static methods...
public static async Task MyMethod()
{
List<Task> tasks = new List<Task>();
// Track your async Tasks
tasks.Add(DoSomethingElseAsync());
tasks.Add(DoSomethingElseAsync());
tasks.Add(DoSomethingElseAsync());
// Wait for Tasks to complete
await Task.WhenAll(tasks);
}
So, my idea is to keep how many AsyncDoSomething() are pending to complete, and only dispose when this count reaches to zero. My initial approach is:
public class MyClass : IDisposable {
private delegate void AsyncDoSomethingCaller();
private delegate void AsyncDoDisposeCaller();
private int pendingTasks = 0;
public DoSomething() {
// Do whatever.
}
public AsyncDoSomething() {
pendingTasks++;
AsyncDoSomethingCaller caller = new AsyncDoSomethingCaller();
caller.BeginInvoke( new AsyncCallback( EndDoSomethingCallback ), caller);
}
public Dispose() {
AsyncDoDisposeCaller caller = new AsyncDoDisposeCaller();
caller.BeginInvoke( new AsyncCallback( EndDoDisposeCallback ), caller);
}
private DoDispose() {
WaitForPendingTasks();
// Finally, dispose whatever managed and unmanaged resources.
}
private void WaitForPendingTasks() {
while ( true ) {
// Check if there is a pending task.
if ( pendingTasks == 0 ) {
return;
}
// Allow other threads to execute.
Thread.Sleep( 0 );
}
}
private void EndDoSomethingCallback( IAsyncResult ar ) {
AsyncDoSomethingCaller caller = (AsyncDoSomethingCaller) ar.AsyncState;
caller.EndInvoke( ar );
pendingTasks--;
}
private void EndDoDisposeCallback( IAsyncResult ar ) {
AsyncDoDisposeCaller caller = (AsyncDoDisposeCaller) ar.AsyncState;
caller.EndInvoke( ar );
}
}
Some issues may occur if two or more threads try to read / write the pendingTasks variable concurrently, so the lock keyword should be used to prevent race conditions:
public class MyClass : IDisposable {
private delegate void AsyncDoSomethingCaller();
private delegate void AsyncDoDisposeCaller();
private int pendingTasks = 0;
private readonly object lockObj = new object();
public DoSomething() {
// Do whatever.
}
public AsyncDoSomething() {
lock ( lockObj ) {
pendingTasks++;
AsyncDoSomethingCaller caller = new AsyncDoSomethingCaller();
caller.BeginInvoke( new AsyncCallback( EndDoSomethingCallback ), caller);
}
}
public Dispose() {
AsyncDoDisposeCaller caller = new AsyncDoDisposeCaller();
caller.BeginInvoke( new AsyncCallback( EndDoDisposeCallback ), caller);
}
private DoDispose() {
WaitForPendingTasks();
// Finally, dispose whatever managed and unmanaged resources.
}
private void WaitForPendingTasks() {
while ( true ) {
// Check if there is a pending task.
lock ( lockObj ) {
if ( pendingTasks == 0 ) {
return;
}
}
// Allow other threads to execute.
Thread.Sleep( 0 );
}
}
private void EndDoSomethingCallback( IAsyncResult ar ) {
lock ( lockObj ) {
AsyncDoSomethingCaller caller = (AsyncDoSomethingCaller) ar.AsyncState;
caller.EndInvoke( ar );
pendingTasks--;
}
}
private void EndDoDisposeCallback( IAsyncResult ar ) {
AsyncDoDisposeCaller caller = (AsyncDoDisposeCaller) ar.AsyncState;
caller.EndInvoke( ar );
}
}
I see a problem with this approach. As the release of resources is asynchronously done, something like this might work:
MyClass myClass;
using ( myClass = new MyClass() ) {
myClass.AsyncDoSomething();
}
myClass.DoSomething();
When the expected behavior should be to launch an ObjectDisposedException when DoSomething() is called outside the using clause. But I don't find this bad enough to rethink this solution.
I've had to just go old-school. No, you can't use the simplified "using" block. But a Using block is simply syntactic sugar for cleaning up a semi-complex try/catch/finally block. Build your dispose as you would any other method, then call it in a finally block.
public async Task<string> DoSomeStuffAsync()
{
// used to be a simple:
// using(var client = new SomeClientObject())
// {
// string response = await client.OtherAsyncMethod();
// return response;
// }
//
// Since I can't use a USING block here, we have to go old-school
// to catch the async disposable.
var client = new SomeClientObject();
try
{
string response = await client.OtherAsyncMethod();
return response;
}
finally
{
await client.DisposeAsync();
}
}
It's ugly, but it is very effective, and much simpler than many of the other suggestions I've seen.
Related
I have a C# Windows IoT Background application I have created. That application has multiple threads in the ThreadPool that run indefinitely.
These threads need to be able to read/write to global variables in the main thread, but I am not sure how to accomplish this. Here is an example of what I am trying to do:
// main task
public sealed class StartupTask : IBackgroundTask
{
private static BackgroundTaskDeferral _Deferral = null;
private static MyThreadClass1 thread1 = null;
private static MyThreadClass2 thread2 = null;
private static MyThreadClass3 thread3 = null;
List<Object> MyDevices = null;
public async void Run(IBackgroundTaskInstance taskInstance)
{
_Deferral = taskInstance.GetDeferral();
MyDevices = GetDeviceList();
thread1 = new MyThreadClass1();
await ThreadPool.RunAsync(workItem =>
{
thread1.Start();
});
thread2 = new MyThreadClass2();
await ThreadPool.RunAsync(workItem =>
{
thread2.Start();
});
thread3 = new MyThreadClass3();
await ThreadPool.RunAsync(workItem =>
{
thread3.Start();
});
}
}
internal class MyThreadClass1
{
public async void Start()
{ }
}
internal class MyThreadClass2
{
public async void Start()
{ }
}
internal class MyThreadClass3
{
public async void Start()
{ }
}
In any of the three threads that are running, I need to be able to read and write to List<Object> MyDevices.
The threads all have different functions, but they all interact with "MyDevices", so if one thread makes a change to that list, the other threads need to know about the change right away.
What is the best way to go about doing this?
Thanks!
These threads need to be able to read/write to global variables in the main thread
The easiest way to deal with this requirement is to remove it. Is it possible to code the solution so that each thread owns a device? Or is it possible to rethink the thread's responsibilities so that they communicate by message passing instead of updating shared data? Usually these alternative approaches result in much cleaner and less buggy code. But not always.
You will need locks to protect shared data. The easiest way to do this is with the lock statement, e.g.:
object _mutex = new object();
List<Object> MyDevices = null;
...
var device = ...;
lock (_mutex)
{
MyDevices.Add(device);
}
Generally, you want to minimize the code in the lock statement. Also, you may want to have one lock for the List<Object> and a separate lock for each item in the list, depending on how your thread use those devices.
One thing you might want to consider using is an ObservableCollection. This class implements the INotifyPropertyChanged interface, which notifies any listeners of changes to the underlying collection.
Next, you'll want to implement an event handler for PropertyChanged in your Thread classes like so (I recommend making either an interface or base class that handles this since you appear to be using different classes for each Thread):
public sealed class MyThreadBase
{
private ObservableCollection<object> MyDevices;
public MyThreadBase(ObservableCollection<object> deviceList)
{
MyDevices = deviceList;
MyDevices.PropertyChanged += MyDevices_PropertyChanged; // Register listener
}
private void MyDevices_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
lock (MyDevices)
{
// Do something with the data...
}
}
}
The lock statement is used so that the thread is blocked when another thread is reading or writing to MyDevices. This is typically important in synchronization and is known as the readers-writers problem. I'd suggest reading up on that and possible solutions as well.
If you intend, however, for each thread to iterate over the devices and do something with each one, then you will run into issues, as iterating over a changing collection is not a good idea (and when using a foreach loop, will actually throw an exception), so keep that in mind too.
other threads need to know about the change right away
If you want low latency notifications, threads must spend the majority of time sleeping on something. E.g. executing Dispatcher.Run() that will sleep waiting for messages/tasks to process.
If that’s your case, you can use ObservableCollection instead of List, and write CollectionChanged handler that forwards notifications for your 3 threads. Or if that’s what you want, forward notifications to 2 other threads, excluding the current one, if you won’t want the thread that initiated the change to process changed event.
I'm not sure if the Dispatcher class is available on Windows IoT platform. Definitely not the case for .NET core. Even if not, high-level building blocks to create one are available. Here’s an example implementation that also implements synchronization context, very simple because relies on high-level ConcurrentQueue and BlockingCollection generic classes.
using kvp = KeyValuePair<SendOrPostCallback, object>;
enum eShutdownReason : byte
{
Completed,
Failed,
Unexpected,
}
class Dispatcher : IDisposable
{
const int maxQueueLength = 100;
readonly ConcurrentQueue<kvp> m_queue;
readonly BlockingCollection<kvp> m_block;
public Dispatcher()
{
m_queue = new ConcurrentQueue<kvp>();
m_block = new BlockingCollection<kvp>( m_queue, maxQueueLength );
createdThreadId = Thread.CurrentThread.ManagedThreadId;
prevContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext( new SyncContext( this ) );
}
readonly SynchronizationContext prevContext;
readonly int createdThreadId;
class SyncContext : SynchronizationContext
{
readonly Dispatcher dispatcher;
public SyncContext( Dispatcher dispatcher )
{
this.dispatcher = dispatcher;
}
// https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
public override void Post( SendOrPostCallback cb, object state )
{
dispatcher.Post( cb, state );
}
}
/// <summary>Run the dispatcher. Must be called on the same thread that constructed the object.</summary>
public eShutdownReason Run()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
while( true )
{
kvp h;
try
{
h = m_block.Take();
}
catch( Exception ex )
{
ex.logError( "Dispatcher crashed" );
return eShutdownReason.Unexpected;
}
if( null == h.Key )
return (eShutdownReason)h.Value;
try
{
h.Key( h.Value );
}
catch( Exception ex )
{
ex.logError( "Exception in Dispatcher.Run" );
}
}
}
/// <summary>Signal dispatcher to shut down. Can be called from any thread.</summary>
public void Stop( eShutdownReason why )
{
Logger.Info( "Shutting down, because {0}", why );
Post( null, why );
}
/// <summary>Post a callback to the queue. Can be called from any thread.</summary>
public void Post( SendOrPostCallback cb, object state = null )
{
if( !m_block.TryAdd( new kvp( cb, state ) ) )
throw new ApplicationException( "Unable to post a callback to the dispatcher: the dispatcher queue is full" );
}
void IDisposable.Dispose()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
SynchronizationContext.SetSynchronizationContext( prevContext );
}
}
Regardless on whether you’ll use built-in Dispatcher or my custom one, all threads must call it’s Run method, then use asynchronous posted tasks, or async methods, to run code within the dispatcher.
Summary
I have a class that uses lock to provide thread-safe access to a private field. However, for reasons detailed below I'm considering switching to using SemaphoreSlim to implement thread-safety. I know that if I surround all access to this field with lock (_lock) (as I currently do), I'm guaranteed that writes to the field will be atomic and that all threads will see the most recently-written value (source). I'm wondering if I get both of these guarantees with SemaphoreSlim, or only the guarantee about atomic writes.
Details
I have an interface I wrote a while back to represent services that can be used for communicating with external devices:
public interface ICommunicationService : IDisposable
{
event EventHandler<ReceivedMessageEventArgs> MessageReceived;
void SendMessage(GenericMessage message);
void Start();
}
I've recently come across a situation where I'd prefer to have an async implementation of these methods, and apparently when you start doing async you need to sort of go the whole hog with it to avoid deadlocks, etc., so I'm planning on updating the interface and all existing implementations that I've written to support asynchronous operation:
public interface ICommunicationService : IDisposable
{
event EventHandler<ReceivedMessageEventArgs> MessageReceived;
Task SendMessage(GenericMessage message);
Task Start();
}
One of my classes that implemented this interface did a bunch of locking in its implementations of SendMessage() and Start():
public virtual void SendMessage(GenericMessage message)
{
CheckDisposed();
lock (_lock)
{
if (CommunicationState != CommunicationState.Up)
{
throw new InvalidOperationException("Message cannot be sent as communication is not established.");
}
try
{
_currentDelegate.SendMessage(message);
}
catch (Exception)
{
TerminateCommunication();
}
}
}
Trying to switch this code to an async implementation, I noticed I couldn't await a task within a lock statement. According to async guru Stephen Cleary's blog post on the subject, the async way of doing this is to use SemaphoreSlim.
Based on that post, I've changed my SendMessage implementation to this:
public virtual async Task SendMessage(GenericMessage message)
{
CheckDisposed();
if (CommunicationState != CommunicationState.Up)
{
throw new InvalidOperationException("Message cannot be sent as communication is not established.");
}
// _mutex = new SemaphoreSlim(0, 1)
await _mutex.WaitAsync().ConfigureAwait(false);
try
{
await _currentDelegate.SendMessage(message);
}
catch (Exception)
{
TerminateCommunication();
}
finally
{
_mutex.Release();
}
}
What I'm wondering though is whether I'm guaranteed that any given thread will see the most recent value of _currentDelegate when it executes await _currentDelegate.SendMessage(message), or whether I need to use another construct to ensure writes are immediately visible to other threads.
In particular, this class has another method TryRestartCommunication:
private bool TryRestartCommunication(bool initialStart)
{
// ...
lock (_lock)
{
// ...
try
{
_currentDelegate = _factory();
_currentDelegate.Start();
_currentDelegate.MessageReceived += MessageReceived;
CommunicationState = CommunicationState.Up;
return true;
}
// ...
}
}
If I re-implement this method to lock on the semaphore and have some Thread A call TryRestartCommunication() and immediately after Thread B call SendMessage(), am I guaranteed that Thread B will see the new value of _currentDelegate set by Thread A?
If not, would a decent solution be to just make _currentDelegate volatile, or to use Interlocked to update its value?
Edit
Got a close vote because apparently this question isn't clear enough. Let me try to make it as clear as possible: if I switch from protecting my critical regions with lock to SemaphoreSlim, do I then need to mark the shared fields as volatile (or something similar) to ensure the same level of thread safety?
If you switch from protecting your critical regions/data by lock() to SemaphoreSlim(1), you will end up with the same level of thread safety.
We have done it several times and never encounter single data protection bug there.
However, be aware that after await xxx.ConfigureAwait(false); you might end in different synchronization context (thread) and the method await _currentDelegate.SendMessage(message); might not be ok with it. For example, if that method access Webform UI controls.
I have an IDisposable object that can be accessed between multiple threads. I am trying to figure out a way to track that the object is "in use" before performing any clean up. In other words, I need to keep some sort of reference count to indicate that there are running methods (which are decremented when they complete) so that the Dispose method wouldn't continue until they are all complete (or after some timeout has passed). But I also need to make sure that once Dispose has been entered that any future calls to Method fail.
Something like:
class MyObject : IDisposable
{
private long _counter;
private bool _stopping;
private IDisposable _someResource;
public void Method()
{
if (_stopping)
throw new InvalidOperationException();
Interlocked.Increment(ref _counter);
try
{
// do some work
}
finally
{
Interlocked.Decrement(ref _counter);
}
}
public void Dispose()
{
var timeout = DateTime.Now.Add(TimeSpan.FromSeconds(15));
while ( DateTime.Now < timeout && Volatile.Read(ref _counter) > 0)
{
// wait
// Thread.Sleep(10) or something
}
_stopping = true;
//perform clean up
_someResource.Dispose();
}
}
However this won't work because Method() may be called again and _stopping hasn't been set but the Dispose would continue, invalidating everything else.
Is there a specific pattern that I can use here or perhaps some framework classes that can be used to solve this? Basically some two-way signal telling Dispose that nothing is in process so its good-to-go while signalling Method that it should fail.
I found CountdownEvent but I'm not sure how I can use it here. This answer shows an example CountdownLatch but it doesn't prevent new work from being requested.
No. Just say no to the Dispose method being responsible for "tracking" all instances consuming the class. The consumers of the class need to handle their clean-up and properly dispose.
If Dispose can be called multiple times by multiple classes, then you've just found a code smell. Only one class should being calling the dispose method; and that class should be tracking the consumers of the class with the Dispose method.
A common pattern for preventing dispose from being called multiple times is to set up a flag, similar to what you have now. Use the ObjectDisposedException as needed:
private bool _zombified;
public void Method()
{
if (_zombified)
throw new ObjectDisposedException();
// method's logic
}
public void Dispose
{
if(_zombified)
{
return;
}
_zombified = true;
// perform clean-up
}
Is there anything wrong with this code or can this be done more efficiently? In particular, i'm a little concerned about the code within parrallel.foreach firing/invoking a delegate. could this potentially cause any issues?
I ask because currently the consumers are unable to keep up with the items being produced in many cases, leading to memory issues.
public delegate void DataChangedDelegate(DataItem obj);
public class Consumer
{
public DataChangedDelegate OnCustomerChanged;
public DataChangedDelegate OnOrdersChanged;
private CancellationTokenSource cts;
private CancellationToken ct;
private BlockingCollection<DataItem> queue;
public Consumer(BlockingCollection<DataItem> queue) {
this.queue = queue;
Start();
}
private void Start() {
cts = new CancellationTokenSource();
ct = cts.Token;
Task.Factory.StartNew(() => DoWork(), ct);
}
private void DoWork() {
Parallel.ForEach(queue.GetConsumingPartitioner(), item => {
if (item.DataType == DataTypes.Customer) {
OnCustomerChanged(item);
} else if(item.DataType == DataTypes.Order) {
OnOrdersChanged(item);
}
});
}
}
In particular, i'm a little concerned about the code within parrallel.foreach firing/invoking a delegate. could this potentially cause any issues?
In general terms, there's nothing wrong with calling a delegate from within the Parallel.ForEach method.
However, it does make it more difficult to control thread safety, as the delegate will take on the requirements to handle all data synchronization correctly. This is mostly an issue since the main reason to use a delegate is to allow the "method" that you're calling to be passed in, which means it's being supplied externally.
This means, for example, that if a delegate happens to call code that tries to update a user interface, you may be in trouble, as it will get called from a background/ThreadPool thread.
System.Collections.Concurrent has some new collections that work very well in multithreaded environments. However, they are a bit limited. Either they block until an item becomes available, or they return default(T) (TryXXX methods).
I'm needing a collection that is thread safe, but instead of blocking the calling thread it uses a callback to inform me that at least one item is available.
My current solution is to use a BlockingCollection, but to use the APM with a delegate to get the next element. In other words, I create a delegate to a method that Takes from the collection, and execute that delegate using BeginInvoke.
Unfortunately, I have to keep a lot of state within my class in order to accomplish this. Worse, the class is not thread safe; it can only be used by a single thread. I'm skirting the edge of maintainability, which I'd prefer not to do.
I know there are some libraries out there that make what I'm doing here pretty simple (I believe the Reactive Framework is one of these), but I'd like to accomplish my goals without adding any references outside of version 4 of the framework.
Are there any better patterns I can use that don't require outside references that accomplish my goal?
tl;dr:
Are there any patterns that satisfy the requirement:
"I need to 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."
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.
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 Take or TryTake as you normally would for a BlockingCollection. 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 Take do not get starved as they do in my second solution.
public class NotifyingBlockingCollection<T> : BlockingCollection<T>
{
private Thread m_Notifier;
private BlockingCollection<Action<T>> m_Callbacks = new BlockingCollection<Action<T>>();
public NotifyingBlockingCollection()
{
m_Notifier = new Thread(Notify);
m_Notifier.IsBackground = true;
m_Notifier.Start();
}
private void Notify()
{
while (true)
{
Action<T> callback = m_Callbacks.Take();
T item = Take();
callback.BeginInvoke(item, null, null); // Transfer to the thread pool.
}
}
public void RegisterForTake(Action<T> callback)
{
m_Callbacks.Add(callback);
}
}
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 Add and RegisterForTake. 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 Take would get starved as callbacks always take priority.
public class NotifyingBlockingCollection<T>
{
private BlockingCollection<T> m_Items = new BlockingCollection<T>();
private Queue<Action<T>> m_Callbacks = new Queue<Action<T>>();
public NotifyingBlockingCollection()
{
}
public void Add(T item)
{
lock (m_Callbacks)
{
if (m_Callbacks.Count > 0)
{
Action<T> 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<T> 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);
}
}
}
}
How about something like this? (The naming could probably use some work. And note that this is untested.)
public class CallbackCollection<T>
{
// Sychronization object to prevent race conditions.
private object _SyncObject = new object();
// A queue for callbacks that are waiting for items.
private ConcurrentQueue<Action<T>> _Callbacks = new ConcurrentQueue<Action<T>>();
// A queue for items that are waiting for callbacks.
private ConcurrentQueue<T> _Items = new ConcurrentQueue<T>();
public void Add(T item)
{
Action<T> callback;
lock (_SyncObject)
{
// Try to get a callback. If no callback is available,
// then enqueue the item to wait for the next callback
// and return.
if (!_Callbacks.TryDequeue(out callback))
{
_Items.Enqueue(item);
return;
}
}
ExecuteCallback(callback, item);
}
public void TakeAndCallback(Action<T> callback)
{
T item;
lock(_SyncObject)
{
// Try to get an item. If no item is available, then
// enqueue the callback to wait for the next item
// and return.
if (!_Items.TryDequeue(out item))
{
_Callbacks.Enqueue(callback);
return;
}
}
ExecuteCallback(callback, item);
}
private void ExecuteCallback(Action<T> callback, T item)
{
// Use a new Task to execute the callback so that we don't
// execute it on the current thread.
Task.Factory.StartNew(() => callback.Invoke(item));
}
}