I have an ASP.NET WebApi request method which in turn starts an asynchronous call using Observable.Using on a legacy resource. This resource will spawn a new thread on which it raises events which in turn are converted to OnNext items in an IObservable stream exposed by a wrapper around the resource.
I am awaiting the result of the stream using IObservable.FirstOrDefaultAsync() and my WebApi method is marked async.
If I go with this setup, I will get the infamous
An asynchronous module or handler
completed while an asynchronous operation was still pending
So, my first question is regarding this. I assume I'm getting this since new asynchronous operations (no async/await) are spawned by the legacy resource, but how exactly does ASP.NET know this? What has been registered? I have found out that ASP.NET is looking at the SynchronizationContext.Current._state.VoidAsyncOutstandingOperationCount in order to raise this exception, but which calls increments this property? Threads queued to the ThreadPool? I am fairly certain this is being made by the legacy resource.
Now why are these operations still going when I'm disposing my resource? Well, it appears Dispose is run on the thread on which events are propagated, similar in concept to the below snippet.
Observable
.Using(
() => {
Console.WriteLine($"Created on thread: {Thread.CurrentThread.ManagedThreadId}");
return Disposable.Create(() => {
Console.WriteLine($"Disposed on thread: {Thread.CurrentThread.ManagedThreadId}");
});
},
_ => Observable.Return(1, NewThreadScheduler.Default))
.Do(_ => Console.WriteLine($"OnNext on thread: {Thread.CurrentThread.ManagedThreadId}"))
.Wait();
Result similar to this:
Created on thread: 10
OnNext on thread: 11
Disposed on thread: 11
Is this by design? When disposing a resource using using, it's obvious that the resource is disposed on the same thread that created it since the code is synchronous. With the Dispose being run on a separate thread, the calling code will continue running and the controller will return before the Dispose is fully completed (most of the time, at least).
How can I mitigate this in a sane way? One way that seem to work is to, instead of using Observable.Using, using this construct which is returned to the controller, awaiting it using FirstOrDefaultAsync():
var resource = // Creating resource manually.
return resource.StartAsyncOperation() // <- observable producing events
.ObserveOn(SynchronizationContext.Current)
.Do(_ => resource.Dispose());
This feels like a hack to me though.
Thoughts and recommendations?
Edit 1
I guess one of the problems I'm facing here is that the Dispose method of the resource is called after the sequence is terminated/completed when I'm using Observable.Using. Should this be the case? There's really no way of waiting for the Dispose using that construct in that case. I'd have to amend the api with an additional IObservable<Unit> Disposed() method or something like that...
The Dispose will be called on the thread that calls it (well duh). To be more helpful, when a Rx sequence is consumed/observed on another thread that is where the OnComplete callback will be called. If you are using Rx with the standard operators, then you will get auto disposal behavior when the sequence terminates (with either OnError or OnComplete). This auto disposal will just happen straight after the OnComplete/OnError and will just run on the same thread.
If you want your disposal to be bound to a scheduler then I would suggest looking at the System.Reactive.Disposables.ScheduledDisposable type. However it appears that using a SynchronizationContext is more natural here, so in that case System.Reactive.Disposables.ContextDisposable is probably more suitable.
Related
Let's say I have a form with a piece of data that needs to be used in an await'ed method as such:
using (var riskForm = new RiskValidationForm(config))
{
if (riskForm.OpenDialog() == DialogResult.Cancel)
return;
await Task.Run(() => MyMethod(riskForm.GetRiskData());
}
Is this dangerous? I'm afraid that the form might dispose, getting rid of what RiskData() returns before the awaited method is started. Hence I'd be calling RiskData() on something that is already disposed of. Is this possible?
Function signature of MyMethod:
private void MyMethod(RiskLimitsConfigurationCollection riskLimits)
No, it's not possible that the Form will be disposed before the completion of the Task. The await inside the using statement ensures that. But even if you removed the using/await combination (making the task essentially fire-and-forget) there would still be no problem. The garbage collector doesn't recycle objects that are still in use. The Task would hold a reference to a closure that would hold a reference to the RiskValidationForm, and Task objects are not recycled before their completion (unless the application is terminated).
You have two other reasons to worry though:
You have to worry about the thread-safety of the MyMethod method. It may be called by multiple threads concurrently, unless there is UI code that prevents it from happening (for example by disabling the activation Button while the task is still running).
You have to worry about the thread-affinity of the GetRiskData method. If this method accesses any method or property of any UI control of the RiskValidationForm form, you have committed a cross-thread violation because you have accessed a UI element from a thread other than the UI thread.
I have a sync method GetReports() which return value will be used to set the data source of a UI control. It may take a while to run. Is it idiomatic way to call it asynchronously as the following?
var l = new List<...>();
await Task.Run(() => l = GetReports().ToList());
UIControl.DataSource = l;
You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive.Windows.Forms and add using System.Reactive.Linq; - then you can do this:
IDisposable subscription =
Observable
.Start(() => GetReports().ToList())
.ObserveOn(UIControl)
.Subscribe(list => UIControl.DataSource = list);
This nicely pushes to a new thread and then pulls it back before updating the DataSource.
If you need to cancel before it has finished just call subscription.Dispose();.
If your call to GetReports is cancellable then you can do this:
IDisposable subscription =
Observable
.FromAsync(ct => GetReports(ct))
.Select(x => x.ToList())
.ObserveOn(UIControl)
.Subscribe(list => UIControl.DataSource = list);
Calling subscription.Dispose() will now also cancel the task.
If you are after responsive UI and to run a long running CPU workload (and not Scalability as such) then this is fine and will achieve what you want. Essentially it will
Start a new thread (term used loosely)
Create a continuation
Give back the thread that calls it (in your case the UI thread)
Execute the workload
Run the continuation
5a Execute everything after the await on the thread you called it on
Although Tasks aren't threads, you will find this will steal a thread from the Thread Pool to do your workload, and it will free up the UI Thread until its finished
You could also do the same thing with the older style Task.Run and ContinueWith.
There is another school of thought as well, that if you use the TaskFactory.StartNew with the TaskCreationOptions as LongRunning it will hint to the Default TaskScheduler that you want to create a thread external to the Thread Pool. This gives the advantage of leaving the Thread Pool with more resources.
On saying that, TaskFactory.StartNew is the grand daddy of the Task creation methods, it has its own quirks, and you probably should only use it when you specifically feel the need to do so. I would just stick with what you have.
The last note, although it seems like a good idea to wrap this workload in a method and call it async, its generally not a good idea; and if you must wrap, its best left to caller to decide these things. So once again you are doing the right thing. Stephen Cleary talks about Fake Async and Async Wrappers and the reasons why you shouldn't have a need to do it in
Task.Run Etiquette and Proper Usage
Consider this method:
//Called on a known thread
public async void ThreadSleep()
{
while(itemsInQueue)
{
//This call is currently on Thread X
await Task.Delay(5000);
//This needs to be on the thread that the method was called on
DoSomeProcessing();
}
}
I am assuming that the Task.Delay is executing async on a different thread and resumes on that same thread. This was not very obvious to me. How do I get the method to continue on Thread X?
PS: The ThreadSleep method executes on a non UI thread
Edit: 1) Added W.Brian's code example for simplicity.
2) Yes, this example is exactly that... an example.
3) The purpose of Thread.Delay is just to add some delay between processing.
You need to create your own synchronization context (like the UI thread does).
There's a pretty good article on MSDN that helps to understand the problem and how to create a solution.
Mind if I ask why you have to continue on the same thread?
Usually it shouldn't create and issues when a new thread is used since the context is preserved.
If you need to preserve some kind of context between calls at a deeper level (like you would do with ThreadLocal), I suggest you use the new AsyncLocal to achieve this goal.
It makes sure that immutable objects stay within the async context even if the thread is changed (refer to: How do the semantics of AsyncLocal differ from the logical call context?).
await Task.Delay(5000).ConfigureAwait(true);
Calling ConfigureAwait(true) should work as it ensures the same context as the original thread even if the thread changes. This assumes that ThreadLocal<T> is not being used, in which case async/await will generally cause problems and Thread.Sleep may be preferred if you can't change the rest of the code.
I'm implementing the Threading concept in that we need to call more then one method simultaneous so for we used
Parallel.Invoke(
() => { GetLink(words); },
() => { GetSA(words); },
() => { Getlp(words); });
This case 1 working fine but. In case 2 we need to call three method and i need to find which method execute first and it has the result in the first method and other 2 method are need to kill or stop execute.it applicable for all the 3 method.
First, read this existing answer: C# Thread Termination and Thread.Abort()
Second, read this another one: What's wrong with using Thread.Abort()
General recommendation is 'never kill or abort a thread'. There are multiple reasons for this, however it is better to read detailed explanations on the web rather then re-post them here every time.
Instead of aborting/killing, modify your code so that sub-tasks can stop themselves gracefully.
You can have a shared CancellationToken (see CancellationTokenSource class), and check its status periodically in every thread's loop(s) - or use it in 'WaitAny' methods.
All threads will set this token at the time when they finish, so the first one to complete will send signal to others to stop.
If you don't have time or willingness to implement graceful stopping, create and run Threads explicitly, Parallel and Tasks are designed for a safer programming style.
On the Thread, you can call Abort method that will throw ThreadAbortException inside the Thread.
I've looked all over and I can't find an answer.
Is it better, worse, or indifferent to use:
{
...
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint);
Control.Invoke(PaintDelegate);
}
protected void RefreshPaint()
{
this.Refresh();
}
...or...
Task.Factory.StartNew(() =>
{
this.Refresh();
},
CancellationToken.None,
TaskCreationOptions.None,
uiScheduler);
Assuming that uiScheduler is a scheduler that will delegate the calls to the UI thread, I would say that functionally, using the two is indifferent (with the exception that the call to Control.Invoke will block until the call completes, whereas the call to Task will not, however, you can always use Control.BeginInvoke to make them semantically equivalent).
From a semantic point of view, I'd say that using Control.Invoke(PaintDelegate) is a much better approach; when using a Task you are making an implicit declaration that you want to perform a unit of work, and typically, that unit of work has the context of being scheduled along with other units of work, it's the scheduler that determines how that work is delegated (typically, it's multi-threaded, but in this case, it's marshaled to the UI thread). It should also be said that there is no clear link between the uiScheduler and the Control which is linked to the UI thread that the call should be made one (typically, they are all the same, but it's possible to have multiple UI threads, although very rare).
However, in using Control.Invoke, the intention of what you want to do is clear, you want to marshal the call to the UI thread that the Control is pumping messages on, and this call indicates that perfectly.
I think the best option, however, is to use a SynchronizationContext instance; it abstracts out the fact that you need to synchronize calls to that context, as opposed to the other two options, which are either ambiguous about the intent in the call (Task) or very specific in the way it is being done (Control.Invoke).
It is not same. First version will block the calling thread until UI thread is ready to invoke the method. For a non blocking version, you should use Control.BeginInvoke, which also returns immediately.
Apart from that (if you are comparing Task to a Thread Pool thread), there is little difference in using them.
[Edit]
In this case, there is no difference between Task.Factory.StartNew and Control.BeginInvoke (but not Invoke as I wrote above), since there is only a single GUI thread which can execute your code. No matter how many calls you make using either of them, they will still execute sequentially when UI thread becomes free.