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.
Related
So we have this class implementing IValueTaskSource This code cannot be written as async-await because there's nothing to await on. We send a message to another running thread and get back a ValueTask that can be awaited by the caller to get the notification that the other thread has finished processing the message. However the other thread is pre-existing and already doing work. It receives the message by a completely other way; processes the message, then needs to tell the threadpool-origin thread that it finished. Thus; IValueTaskSource
There is no stock ValueTaskSource (not getting into whether or not there should be; however in this case a stock version would be of questionable utility). What we actully have looks very much like this:
class Message : IValueTaskSource {
public ValueTask Send()
{
/* how the message is sent is irrelevant */
return new ValueTask(this, 0);
}
private Action<object> continuation;
private object continuationState;
void IValueTaskSource.OnCompleted(Action<object> continuation, object state, short _, ValueTaskSourceOnCompletedFlags __)
{
lock(this) {
if (GetStatus(_) == ValueTaskSourceStatus.Pending)
{
this.continuation = continuation;
this.continuationState = state;
return;
}
continuation(continuationState); /* Suspect */
}
}
public void SetCompleted()
{
lock (this)
{
/* set state completed omitted for brevity */
continuation?.Invoke(continuationState); /* Suspect */
}
}
}
I think I'm doing this wrong. Imagine a large chain of these; it seems like it would build up too much stack. In particular, the lines marked /* Suspect */ are exactly that; and ValueTaskSourceOnCompletionFlags is unused. Although it does have the nicety in that an exception thrown by continuation always goes somewhere; assuming that's even a real issue.
Right now, the code works because there are only three of them and the continuations that use them are very much thread agnostic which thread they are on.
Based on the link to ManualResetValueTaskSource provided by Stephen Cleary and the corresponding source code I was able to produce an answer.
ManualResetValueTaskSourceCore<T> provides a complete implementation of IValueTaskSource<T> and IValueTaskSource<T>. This is currently a case of there's no void implementation so create a void implementation with a dummy type. There's some generalized debate on whether bool or object is the best dummy type but I think it doesn't really matter because member padding of T will force alignment anyway.
So the answer is to forward all the methods.
public ValueTask Send()
{
/* how the message is sent is irrelevant */
return CraeteValueTask();
}
private ManualResetValueTaskSourceCore<object> taskSource;
private ValueTask CreateValueTask() => new ValueTask(this, taskSource.Version);
public ValueTaskSourceStatus GetStatus(short version) => taskSource.GetStatus(version);
public void OnCompleted(Action<object> continuation, object state, short version, ValueTaskSourceOnCompletedFlags flags) => taskSource.OnCompleted(continuation, state, version, flags);
public void SetCompleted() => taskSource.SetResult(null);
In this case each message is in its own object so there's no pooling. Doesn't matter. Calling the existing implementation is so much easier than trying to write down the smallest correct implementation that it's still the better way.
I'm pretty sure if I were pooling value task sources the correct way would be to call Reset() inside CreateValueTask().
Here is an example using the INotifyCompletion interface to get the notification, instead of the heavier IValueTaskSource+ValueTask mechanism. The Message class is amended with just one additional instance field, an Action, and it has become awaitable by exposing a GetAwaiter method. Each Message instance is intended to be awaited only once.
public class Message : INotifyCompletion
{
private static readonly Action _completedSentinel = new(() => { });
private Action _continuation;
public Message GetAwaiter() { return this; }
public bool IsCompleted
=> ReferenceEquals(Volatile.Read(ref _continuation), _completedSentinel);
public void OnCompleted(Action continuation)
{
Action original = Interlocked.CompareExchange(ref _continuation,
continuation, null);
if (original is null) return; // Normal case
if (ReferenceEquals(original, _completedSentinel))
continuation(); // Rare case
else
throw new InvalidOperationException("Double await");
}
public void GetResult() { }
public void SetCompleted()
{
Action continuation = Interlocked.Exchange(ref _continuation,
_completedSentinel);
if (continuation is null) return;
ThreadPool.QueueUserWorkItem(state => ((Action)state).Invoke(), continuation);
}
}
Online demo.
The static _completedSentinel field is used in order to resolve a race condition that might occur, between the thread that awaits and the thread that invokes the SetCompleted method. Normally the await will happen first, but the implementation above will not break if it happens after the SetCompleted, or even if the SetCompleted is invoked between the IsCompleted/OnCompleted calls (these are called by the async/await machinery).
Overview
I am attempting to write an IAsyncEnumerable<T> wrapper around an IObserver<T> interface. At first I used a BufferBlock<T> as the backing data store, but I found out through performance testing and research that it is actually a pretty slow type, so I decided to give the System.Threading.Channels.Channel type a go. I had a similar problem with my BufferBlock implementation as this one but this time I'm not sure how to resolve it.
Problem
My GetAsyncEnumerator() loop gets blocked by the await _channel.Reader.WaitToRead(token) call if my IObserver<T>.OnNext() method hasn't written to the _channel yet. What is the correct way to wait for a value to be available to yield in this context without blocking program execution?
Implementation
public sealed class ObserverAsyncEnumerableWrapper<T> : IAsyncEnumerable<T>,
IObserver<T>, IDisposable
{
private readonly IDisposable _unsubscriber;
private readonly Channel<T> _channel = Channel.CreateUnbounded<T>();
private bool _producerComplete;
public ObserverAsyncEnumerableWrapper(IObservable<T> provider)
{
_unsubscriber = provider.Subscribe(this);
}
public async void OnNext(T value)
{
Log.Logger.Verbose("Adding value to Channel.");
await _channel.Writer.WriteAsync(value);
}
public void OnError(Exception error)
{
_channel.Writer.Complete(error);
}
public void OnCompleted()
{
_producerComplete = true;
}
public async IAsyncEnumerator<T> GetAsyncEnumerator(
[EnumeratorCancellation] CancellationToken token = new CancellationToken())
{
Log.Logger.Verbose("Starting async iteration...");
while (await _channel.Reader.WaitToReadAsync(token) || !_producerComplete)
{
Log.Logger.Verbose("Reading...");
while (_channel.Reader.TryRead(out var item))
{
Log.Logger.Verbose("Yielding item.");
yield return item;
}
Log.Logger.Verbose("Awaiting more items.");
}
Log.Logger.Verbose("Iteration Complete.");
_channel.Writer.Complete();
}
public void Dispose()
{
_channel.Writer.Complete();
_unsubscriber?.Dispose();
}
}
Additional Context
It shouldn't matter, but at runtime the IObservable<T> instance passed into the constructor is a CimAsyncResult returned from async calls made to the Microsoft.Management.Infrastructure apis. Those make use of the Observer design pattern which I'm trying to wrap with the fancy new async enumeration pattern.
Edit
Updated with logging to the debugger output and made my OnNext() method async/await as one commenter suggested. You can see it never enters the while() loop.
Further up the call stack I was calling the async method syncronously via the GetAwaiter().GetResult() methods.
Yup, that's a problem.
I did this because in once case I wanted to get the data from within a constructor. I changed that implementation to execute the call using Task.Run() and now the iterators run flawlessly with both implementations.
There are better solutions than blocking on asynchronous code. Using Task.Run is one way to avoid the deadlock, but you still end up with a sub-par user experience (I'm assuming yours is a UI application, since there is a SynchronizationContext).
If the asynchronous enumerator is used to load data for display, then a more proper solution is to (synchronously) initialize the UI to a "Loading..." state, and then update that state as the data is loaded asynchronously. If the asynchronous enumerator is used for something else, you may find some appropriate alternative patterns in my async constructors blog post.
I'm currently self-teaching myself C# and I'm a bit new at programming so apologies in advance if this is covered in another topic (I tried searching).
I've been trying to make a generic worker / thread class that takes in a method which specifically wraps around a long set of procedural steps. The idea is to be able to pause/resume it a manner similar to setting breakpoints to pause/unpause in Visual Studio. To provide context, I'm mostly working with automation with an ASP.NET and XAML WPF interface (XAML at the moment).
My understanding is that I need to use delegates of some sort but I'm looking for a very simple example in plain English. The examples I found are a completely different scope and I have a hard time following the provided solutions in other contexts.
From other examples on MSDN and Stackoverflow, the "Task" worker class is what I have so far, but I'm a bit at a loss on where to on DoDelegatedMethod and my constructor. What I'm trying to do here is to instantiate a Task object, pass in a delegated method on new instantiation, create a new thread, and marry the passed in method to the thread.
The reason why I want a general "Task" is so I can manage specific methods generically instead of having to write a different "DoWork" method for each instance.
Is this the right approach?
class Task
{
private ManualResetEvent _shutdownFlag = new ManualResetEvent(false);
private ManualResetEvent _pauseFlag = new ManualResetEvent(true);
private delegate void MyDelegate();
Thread _thread;
public Task() { }
public Task(MyDelegate d = new MyDelegate(DoStuff)) // ERROR
{
_thread = new Thread(DoDelegatedMethod); // ERROR
}
public void Start()
{
_thread.Start();
}
public void Resume()
{
_pauseFlag.Set(); ;
}
public void Stop()
{
_shutdownFlag.Set();
_pauseFlag.Set();
_thread.Join();
}
private void DoDelegatedMethod(MyDelegate d)
{
do
{
d();
}
while (!_shutdownFlag.WaitOne(0));
}
// This does nothing but spin forever until I force it to stop
public void Spin()
{
do
{
// MessageBox.Show("test");
_pauseFlag.WaitOne(Timeout.Infinite);
}
while (!_shutdownFlag.WaitOne(0));
//MessageBox.Show("thread over");
}
}
new Thread() takes a ThreadStart (or ParameterisedThreadStart) argument, and your DoDelegatedMethod callback doesn't have the right signature for ThreadStart. So you need to write something like this:
ThreadStart method = new ThreadStart(() => DoDelegatedMethod(d));
_thread = new Thread(method);
This creates an anonymous callback (the () => DoDelegatedMethod(d) bit) which when run will call DoDelegatedMethod with the delegate d (which is 'captured' by the anonmyous method). Now you pass this anonymous callback to the Thread constructor, so when the thread runs, it will call the anonymous callback, which will in turn call DoDelegatedMethod(d). Effectively the lambda adapts DoDelegatedMethod to the ThreadStart signature.
Another way to do this would be to change DoDelegatedMethod to take no arguments, and store d as a member field of the Task class which DoDelegateMethod would access.
Also, the reason you get an error on your constructor is that default values can only be of a limited set of types, and delegates aren't one of them (only types that are allowed in attributes, like int, long, string and Type are permitted). Use an overload instead:
public Task() : this(new MyDelegate(DoStuff)) { ... }
public Task(MyDelegate d) { ... }
Note you may still get an error if DoStuff is an instance method of Task -- it's not clear. Personally I think having a default delegate for Task to run is a bit of an odd design, so you may just want to get rid of the default constructor.
Following the discussion in the comments I thought it was worth summarising the suggested revisions to the Task class:
public class Task
{
private readonly Action _action;
// other members as before
// default constructor removed
public Task(Action action)
{
_action = action;
}
public void Start()
{
ThreadStart ts = new ThreadStart(DoDelegatedMethod);
_thread = new Thread(ts);
_thread.Start();
}
private void DoDelegatedMethod()
{
do
{
_action();
}
while (!_shutdownFlag.WaitOne(0));
}
// other members as before
}
And the usage:
Task task = new Task(this.AutomatedTasks);
task.Start();
private void AutomatedTasks() { ... }
You may find good implementation of Task Pool manager here
www.codeproject.com/KB/threads/smartthreadpool.aspx
smartthreadpool allows to send in pool any task,
but you have to add Pause\Start functions to it.
I would model this a List which I would enumerate like you would any other list and use 'yield' at the en of the enumerator.
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));
}
}
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.