OK first of all, it's nothing that I need to implement or anything. I just need to know the answer because someone more experienced told me that asynchronous execution doesn't necessarily have to involve a new thread as threads are somewhat heavy constructs, which confused me a lot and I couldn't agree.
Now let's say, I have two methods - Execute() and ExecuteAsync(). Execute() is running on the main thread. I want to call ExecuteAsync() from within Execute() and I don't care whenever it completes executing, but when it does, may be (or may be not) I want use it's return value. That's a typical example of an asynchronous execution, right?
I know I can do this using BackgroundWorker or IAsyncResult (Delegate.BeginInvoke()), but AFAIK under the hood they spawns a secondary CLR Thread/ThreadPool Thread.
So is it anyhow possible to execute the method ExecuteAsync() asynchronously without the help of a second thread?
EDIT : I think this edit will clarify the scenario further. Invoking ExecuteAsync() is NOT the only (or last) task for Execute() to perform. Execute() should continue it's own tasks without caring about the execution of ExecuteAsync() method.
Here is an example of a program that uses asynchrony and never ever uses more than one thread:
public class Foo
{
private int _value;
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public int Value
{
get
{
return _value;
}
set
{
_value = value;
var oldTCS = tcs;
tcs = new TaskCompletionSource<bool>();
oldTCS.SetResult(true);
}
}
public Task ValueChanged()
{
return tcs.Task;
}
}
private static void Main(string[] args)
{
Foo foo = new Foo();
foo.ValueChanged()
.ContinueWith(t =>
{
Console.WriteLine(foo.Value);
}, TaskContinuationOptions.ExecuteSynchronously);
foo.Value = 5;
}
The Task returned from ValueChanged will be completed the next time that Value is changed. The user of the Foo class can get that returned task and wire up continuations to run on that task based on an operation that has not yet happened. Then, at some point in the future, the value of foo is changed, and the continuation will run. Note that the foo object could be passed to some other function, entirely unknown to Main, that ends up setting the value (to show why you might want to do something like this).
No new thread is needed to create the Task, nor to execute the continuation.
Here's another example that's much more practical:
We'll start with this simple (extension) method that takes a form and returns a Task indicating when that form is next closed:
public static class FormExtensions
{
public static Task WhenClosed(this Form form)
{
var tcs = new TaskCompletionSource<bool>();
form.FormClosed += (sender, args) => tcs.SetResult(true);
return tcs.Task;
}
}
Now we can have this in one of our forms:
private async void button1_Click(object sender, EventArgs args)
{
Form2 otherForm = new Form2();
otherForm.Show();
await otherForm.WhenClosed();
//take some data from that form and display it on this form:
textBox1.Text = otherForm.Name;
}
Creating and showing another form never involves the creation of new threads. Both this form and the new form use entirely the one UI thread to be created and modified.
The creation of the Task returned from WhenClosed does not need to create a new thread at all.
When the Task is awaited, no new thread is created. The current method ends and the UI thread is left to go back to processing messages. At some point, that same UI thread will do something that results in the second form being closed. That will result in the continuation of the task running, thus returning us to our button click handler where we set the text of the textbox.
All of this is done entirely with the UI thread, no other threads have been created. And yet we've just "waited" (without actually waiting) for a long running operation to finish (the user to put some information into the second form and then close it) without blocking the UI thread, thus keeping the main form responsive.
So is it anyhow possible to execute the method ExecuteAsync() asynchronously without the help of a second thread?
It is possible for some methods to run asynchronously without using a new thread. This can be done via Asynchronous I/O with a signal, for example. Most of the framework's new Async methods added in .NET 4.5 async IO whenever possible instead of threads.
This is why it's a good idea to not assume asynchronous == new thread. While asynchrony can be implemented using threading, it is not always implemented this way. It's better to just think of an asynchronous operation as an operation that (hopefully) will not block, and will complete at some point in the future.
Coroutines are a common way to implement several logical threads using a single physical thread. Older operating systems used this and other related concepts to implement cooperative multitasking.
In this context you may also be interested in continuation-passing style and Eric Lippert has a good blog series on this very topic - Part 1, Part 2, Part 3, Part 4, Part 5.
Related
I need to do some work on a specific thread (for all intents and purposes, we can say this is the UI thread), but the method requesting that work to be done may or may not be executing in a different thread. I am completely new to multithreaded programming, but have arrived at the conclusion that the correct approach to this is to use a TaskScheduler.
After toying around for a while with a custom implementation, I found FromCurrentSynchronizationContext. This appears to do exactly what I need and save me a lot of trouble (famous last words and all that).
My question comes down to whether I am overlooking anything that will get me into trouble, or maybe I'm overcomplicating the issue altogether. Here's what I'm doing now:
TaskScheduler
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Internals
{
internal static class MainThreadTaskScheduler
{
private static readonly object taskSchedulerLock = new();
private static readonly Thread taskSchedulerThread;
private static readonly TaskScheduler taskScheduler;
static MainThreadTaskScheduler()
{
lock (taskSchedulerLock)
{
// despite calling it the "main thread", we don't really care which thread
// this is initialized with, we just need to always use the same one for
// executing the scheduled tasks
taskSchedulerThread = Thread.CurrentThread;
if (SynchronizationContext.Current is null)
{
// in implementation this may be null, a default context works
SynchronizationContext.SetSynchronizationContext(new());
}
taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
}
public static Task Schedule(Action action)
{
lock (taskSchedulerLock)
{
if (Thread.CurrentThread == taskSchedulerThread)
{
// if we are already on the main thread, just run the delegate
action();
return Task.CompletedTask;
}
return Task.Factory.StartNew(action, CancellationToken.None,
TaskCreationOptions.None, taskScheduler);
}
}
public static Task<TResult> Schedule<TResult>(Func<TResult> func)
{
lock (taskSchedulerLock)
{
if (Thread.CurrentThread == taskSchedulerThread)
{
// if we are already on the main thread, just run the delegate
return Task.FromResult(func());
}
return Task.Factory.StartNew(func, CancellationToken.None,
TaskCreationOptions.None, taskScheduler);
}
}
}
}
Usage
// ...elsewhere...
public static bool RunTaskInMainThread()
{
// we need to synchronously return the result from the main thread regardless of
// which thread we are currently executing in
return MainThreadTaskScheduler.Schedule(() => SomeMethod()).GetAwaiter().GetResult();
}
I had attempted to make RunTaskInMainThread an async method and use await, but it kept causing my program to hang rather than yielding a result. I'm sure I was just using that incorrectly, but I don't know how to implement it here (bonus question: how can I use await here?).
Am I doing anything wrong here? Is there a better way to get the same results?
You are not in the right direction. Not because you are not smart, but because in the general area that you are trying to move there are traps all over the place.
The TaskSchedulers are not compatible with async/await. They were invented before async/await was a thing, for tasks that we now call delegate-based tasks (tasks that represent the completion of a specific delegate), in contrast with the kind of tasks that are created by async methods and are now known as promise-style tasks (tasks that represent just a promise that sometime in the future they'll complete).
The SynchronizationContext class is useless by itself. It's only useful as a base class for implementing derived classes like the WindowsFormsSynchronizationContext or Stephen Cleary's AsyncContextSynchronizationContext. It's a pity that this class was not defined as abstract, like the TaskScheduler is, to prevent programmers from trying to use it as is. Implementing a proper SynchronizationContext-derived class is not trivial.
When a thread is used for scheduling work via a scheduler, either a TaskScheduler or a SynchronizationContext, the thread is then owned by the scheduler. You can't have a thread that is shared by two schedulers, or by a scheduler and some method that wants to use that thread at any time on demand. That's why when start a message loop on the UI thread with the Application.Run method, this call is blocking. Any code that follows this call will not execute before the loops is completed (before the associated windows Form is closed). The same is true and with Stephen Cleary's AsyncContext. The AsyncContext.Run call is blocking (example).
Some more links:
ParallelExtensionsExtras Tour – #7 – Additional TaskSchedulers
ParallelExtensionsExtras source code
A bare-bone SingleThreadTaskScheduler implementation
I am new to TPL and I am wondering: How does the asynchronous programming support that is new to C# 5.0 (via the new async and await keywords) relate to the creation of threads?
Specifically, does the use of async/await create a new thread each time that they are used? And if there many nested methods that use async/await, is a new thread created for each of those methods?
In short NO
From Asynchronous Programming with Async and Await : Threads
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active. You can use Task.Run to move CPU-bound work to a
background thread, but a background thread doesn't help with a process
that's just waiting for results to become available.
According to MSDN : async keyword
An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.
Here is a sample code to check it :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
private void Print(string txt)
{
string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
}
private void Run()
{
Print("Program Start");
Experiment().Wait();
Print("Program End. Press any key to quit");
Console.Read();
}
private async Task Experiment()
{
Print("Experiment code is synchronous before await");
await Task.Delay(500);
Print("Experiment code is asynchronous after first await");
}
}
And the result :
We see the code of Experiment() method after await executes on another Thread.
But if I replace the Task.Delay by my own code (method SomethingElse) :
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
private void Print(string txt)
{
string dateStr = DateTime.Now.ToString("HH:mm:ss.fff");
Console.WriteLine($"{dateStr} Thread #{Thread.CurrentThread.ManagedThreadId}\t{txt}");
}
private void Run()
{
Print("Program Start");
Experiment().Wait();
Print("Program End. Press any key to quit");
Console.Read();
}
private async Task Experiment()
{
Print("Experiment code is synchronous before await");
await SomethingElse();
Print("Experiment code is asynchronous after first await");
}
private Task SomethingElse()
{
Print("Experiment code is asynchronous after first await");
Thread.Sleep(500);
return (Task.CompletedTask);
}
}
I notice the thread remains the same !
In conclusion, I'll say async/await code could use another thread, but only if the thread is created by another code, not by async/await.
In this case, I think Task.Delay created the thread, so I can conclude async/await does not create a new Thread like said by #Adriaan Stander.
Sorry for being late to the party.
I am new to TPL and I am wondering: How does the asynchronous
programming support that is new to C# 5.0 (via the new async and await
keywords) relate to the creation of threads?
async/await is not introduced for thread creation, but to utilize the current thread optimally.
Your app might read files, wait for response from another server or even do a computation with high memory access (Simply any IO task). These tasks are not CPU intensive (Any task that will not use 100% of your thread).
Think about the case when you are processing 1000 non CPU intensive tasks. In this case, process of creating 1000s of OS level thread might eat up more CPU and Memory than doing actual work on a single thread (4mb per thread in Windows, 4MB * 1000 = 4GB). At the same time if you run all the tasks sequentially, you might have to wait until the IO tasks gets finished. Which end up in long time to complete the task, while keeping the CPU idle.
Since we require parallelism to complete multiple tasks quickly, at the same time all parallel tasks are not CPU hungry, but creating threads is inefficient.
The compiler will break the execution at any method call to an async method (which gets called with an await) and immediately execute the code outside of the current code branch, once an await is reached, the execution will go inside the previous async. This will be repeated again and again until all the async calls are completed and their awaiters are satisfied.
If any of the async method have heavy CPU load without a call to an async method, then yes, your system will become unresponsive and all the remaining async methods will not get called until the current task is finished.
So I've been reading up on the threading model, and Async / Await can certainly lead to new threads being used (not necessarily created - the pool creates them at application start). It's up to the scheduler to determine if a new thread is needed. And as I see it, a call to an awaitable function may have internal details that increase the chances of the scheduler utilizing another thread; simply because more work means more opportunities / reasons for the scheduler to divvy out work.
WinRT async operations automatically happen on the thread pool. And typically you will be calling FROM the thread pool, except for UI thread work .. Xaml/Input/Events.
Async operations started on Xaml/UI threads have their results delivered back to the [calling] UI thread. But asynchronous operation results started from a thread pool thread are delivered wherever the completion happens, which may not be the same thread you were on before. The reason behind this is that code written for the thread pool is likely to be written to be thread safe and it is also for efficiency, Windows doesn't have to negotiate that thread switch.
So again, in answer to the OP, new threads are not necessarily created but your application can and will use multiple threads to complete asynchronous work.
I know this seems to contradict some of the literature regarding async / await, but that's because although the async / await construct is not by itself multithreaded. Awaitables are the, or one of the mechanisms by which the scheduler can divide work and construct calls across threads.
This is at the limit of my knowledge right now regarding async and threading, so I might not have it exactly right, but I do think it's important to see the relationship between awaitables and threading.
Using Async/Await doesn't necessarily cause a new thread to be created. But the use of Async/Await can lead to a new thread to be created because the awaitable function may internally spawn a new thread. And it often does, making the statement 'No, it doesn't spawn threads' almost useless in practice. For example, the following code spawns new threads.
VisualProcessor.Ctor()
{
...
BuildAsync();
}
async void BuildAsync()
{
...
TextureArray dudeTextures = await TextureArray.FromFilesAsync(…);
}
public static async Task<TextureArray> FromFilesAsync(...)
{
Debug.WriteLine("TextureArray.FromFilesAsync() T1 : Thread Id = " + GetCurrentThreadId());
List<StorageFile> files = new List<StorageFile>();
foreach (string path in paths)
{
if (path != null)
files.Add(await Package.Current.InstalledLocation.GetFileAsync(path)); // << new threads
else
files.Add(null);
}
Debug.WriteLine("TextureArray.FromFilesAsync() T2 : Thread Id = " + GetCurrentThreadId());
...
}
In case of Java Spring Framework, a method annotated with #Async runs in a separate thread. Quoting from official guide (https://spring.io/guides/gs/async-method) -
The findUser method is flagged with Spring’s #Async annotation,
indicating that it should run on a separate thread. The method’s
return type is CompletableFuture instead of User, a requirement
for any asynchronous service.
Of course in the backend it uses a Thread Pool and a Queue (where async tasks wait for a thread to be back in the pool).
I would please like to know where I can get an example of multithreading or asynchronous threading.
In the application that I am busy with I have to run a thread in the background of my application to fetch a value that is changing. And whenever this value reaches a certain amount then it needs to call another function. All this has to run in the background of the program so that the user can still do something else on the application.
Any examples or links that could help would really be appreciated.
In order to summarize the options, I will try to list them here (maybe it would be a good idea to make this a community wiki).
First of all, you can simply start a function in another thread:
Thread t = new Thread( ThreadProc );
t.Start();
// now you can wait for thread to finish with t.Join() or just continue
// Thread.IsBackground allows to control how thread lifetime influences
// the lifetime of the application
...
static void ThreadProc() {...} // can also be non-static, but for simplicity....
Then you can use BackgroundWorker:
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += MyFunction;
bgWorker.RunWorkerAsync();
voud MyFunction(object o, DoWorkEventArgs args) {...}
You can use ProgressChanged and RunWorkerCompleted events for more control (as well as WorkerReportsProgress and other properties)
Another option is to use ThreadPool, if your method will not take too much time:
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
...
static void ThreadProc(Object stateInfo) { ... }
Yet another option is to call BeginInvoke on a delegate:
public delegate int MyDelegate(...);
MyDelegate del = SomeFunction;
IAsyncResult ar = del.BeginInvoke(...);
int result = del.EndInvoke(ar);
This will execute on a thread from the thread pool. If you need to wait on calling thread, you can use IAsyncResult.IsCompleted, but it will block the calling thread.
And of course, you can use Task:
var task = Task.Factory.StartNew(() => MyMethod());
This will also execute MyMethod on a thread from the thread pool, so the same warnings apply (although you can use TaskCreationOptions.LongRunning to ensure that the new thread is always created). Under some circumstances (when you wait on task) it can even execute on the same thread, but it is well optimized so you should not worry about that.
This is probably the option with best tradeoff of simplicity vs control (of course, there is no really 'the best'). Here are the benefits (shamelessly stolen from Jon Skeet's answer):
Adding continuations (Task.ContinueWith)
Waiting for multiple tasks to complete (either all or any)
Capturing errors in the task and interrogating them later
Capturing cancellation (and allowing you to specify cancellation to start with)
Potentially having a return value
Using await in C# 5
Better control over scheduling (if it's going to be long-running, say so when you create the task so the task scheduler can take that into account)
Well depending on the level of control that you seek a BackgroundWorker could easily work and its found within the System.ComponentModel.BackgroundWorker. Now here is a link to the MSDN docs on the subject matter : http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
a Simple usecase secenario is like so:
BackgrouWorker BG = new BackgroudWorker();
GB.DoWork += YourFunctionDelegate(object Sender, EventArgs e);
GB.RunWorkerAsync();
Now YourFunctionDelegate(object Sender,EventArgs e) should be what ever it is you want run in the background. However needs to follow this argument form, There are also a good amount of helper functions associated with the backgroundworker like onProgressChanged event that allows monitoring of obviously progress, which if you are new to threading can prove to be a pain at first if you try to make your own threads.
If you would like more control over execution and how the threads function you should take a look at the Task-Parallel-Library here: http://msdn.microsoft.com/en-us/library/dd460717.aspx Which has copious amount of information about multi-threading.
Also here is a great tutorial on how to create a C# thread: http://support.microsoft.com/default.aspx?scid=kb;en-us;815804
For an overview of asynchronous programming on Windows 8 in .Net 4.5:
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
For .Net 4.0 and older you can use the ThreadPool
System.Threading.ThreadPool.QueueUserWorkItem(obj =>
{
// Do some work
for (int i = 0; i < 1000; i++)
Math.Sin(i);
// Get back to the UI thread
App.Current.MainWindow.Dispatcher.BeginInvoke(
new Action(delegate
{
block.Text = "Done!";
}));
});
I have a blog post that compares and contrasts various implementations of background tasks, with advantages and disadvantages for each. Spoiler: Task is definitely the best option. Also, I recommend Task.Run over TaskFactory.StartNew.
If your background operation is truly asynchronous, then you may not need any background threading at all. LINQPad has a set of async examples that are a great starting point. These are more up-to-date than the chapter on threading (by the same author) that others have recommended.
[This appears to be a loooong question but I have tried to make it as clear as possible. Please have patience and help me...]
I have written a test class which supports an Async operation. That operation does nothing but reports 4 numbers:
class AsyncDemoUsingAsyncOperations
{
AsyncOperation asyncOp;
bool isBusy;
void NotifyStarted () {
isBusy = true;
Started (this, new EventArgs ());
}
void NotifyStopped () {
isBusy = false;
Stopped (this, new EventArgs ());
}
public void Start () {
if (isBusy)
throw new InvalidOperationException ("Already working you moron...");
asyncOp = AsyncOperationManager.CreateOperation (null);
ThreadPool.QueueUserWorkItem (new WaitCallback (StartOperation));
}
public event EventHandler Started = delegate { };
public event EventHandler Stopped = delegate { };
public event EventHandler<NewNumberEventArgs> NewNumber = delegate { };
private void StartOperation (object state) {
asyncOp.Post (args => NotifyStarted (), null);
for (int i = 1; i < 5; i++)
asyncOp.Post (args => NewNumber (this, args as NewNumberEventArgs), new NewNumberEventArgs (i));
asyncOp.Post (args => NotifyStopped (), null);
}
}
class NewNumberEventArgs: EventArgs
{
public int Num { get; private set; }
public NewNumberEventArgs (int num) {
Num = num;
}
}
Then I wrote 2 test programs; one as console app and another as windows form app. Windows form app works as expected when I call Start repeatedly:
But console app has hard time ensuring the order:
Since I am working on class library, I have to ensure that my library works correctly in all app models (Haven't tested in ASP.NET app yet). So I have following questions:
I have tested enough times and it appears to be working but is it OK to assume above code will always work in windows form app?
Whats the reason it (order) doesn't work correctly in console app? How can I fix it?
Not much experienced with ASP.NET. Will the order work in ASP.NET app?
[EDIT: Test stubs can be seen here if that helps.]
Unless I am missing something then given the code above I believe there is no way of guaranteeing the order of execution. I have never used the AsyncOperation and AsyncOperationManager class but I looked in reflector and as could be assumed AsyncOperation.Post uses the thread pool to execute the given code asynchronously.
This means that in the example you have provided 4 tasks will be queued to the thread pool synchronously in very quick succession. The thread pool will then dequeue the tasks in FIFO order (first in first out) but it's entirely possible for one of later threads to be scheduled before an earlier one or one of the later threads to complete before an earlier thread has completed its work.
Therefore given what you have there is no way to control the order in the way you desire. There are ways to do this, a good place to look is this article on MSDN.
http://msdn.microsoft.com/en-us/magazine/dd419664.aspx
I use a Queue you can then Enqueue stuff and Dequeue stuff in the correct order. This solved this problem for me.
The documentation for AsyncOperation.Post states:
Console applications do not synchronize the execution of Post calls. This can cause ProgressChanged events to be raised out of order. If you wish to have serialized execution of Post calls, implement and install a System.Threading.SynchronizationContext class.
I think this is the exact behavior you’re seeing. Basically, if the code that wants to subscribe to notifications from your asynchronous event wants to receive the updates in order, it must ensure that there is a synchronization context installed and that your AsyncOperationManager.CreateOperation() call is run inside of that context. If the code consuming the asynchronous events doesn’t care about receiving them in the correct order, it simply needs to avoid installing a synchronization context which will result in the “default” context being used (which just queues calls directly to the threadpool which may execute them in any order it wants to).
In the GUI version of your application, if you call your API from a UI thread, you will automatically have a synchronization context. This context is wired up to use the UI’s message queueing system which guarantees that posted messages are processed in order and serially (i.e., not concurrently).
In a Console application, unless if you manually install your own synchronization context, you will be using the default, non-synchronizing threadpool version. I am not exactly sure, but I don’t think that .net makes installing a serializing synchronization context very easy to do. I just use Nito.AsyncEx.AsyncContext from the Nito.AsyncEx nuget package to do that for me. Basically, if you call Nito.AsyncEx.AsyncContext.Run(MyMethod), it will capture the current thread and run an event loop with MyMethod as the first “handler” in that event loop. If MyMethod calls something that creates an AsyncOperation, that operation increments an “ongoing operations” counter and that loop will continue until the operation is completed via AsyncOperation.PostOperationCompleted or AsyncOperation.OperationCompleted. Just like the synchronization context provided by a UI thread, AsyncContext will queue posts from AsyncOperation.Post() in the order it receives them and run them serially in its event loop.
Here is an example of how to use AsyncContext with your demo asynchronous operation:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting SynchronizationContext");
Nito.AsyncEx.AsyncContext.Run(Run);
Console.WriteLine("SynchronizationContext finished");
}
// This method is run like it is a UI callback. I.e., it has a
// single-threaded event-loop-based synchronization context which
// processes asynchronous callbacks.
static Task Run()
{
var remainingTasks = new Queue<Action>();
Action startNextTask = () =>
{
if (remainingTasks.Any())
remainingTasks.Dequeue()();
};
foreach (var i in Enumerable.Range(0, 4))
{
remainingTasks.Enqueue(
() =>
{
var demoOperation = new AsyncDemoUsingAsyncOperations();
demoOperation.Started += (sender, e) => Console.WriteLine("Started");
demoOperation.NewNumber += (sender, e) => Console.WriteLine($"Received number {e.Num}");
demoOperation.Stopped += (sender, e) =>
{
// The AsyncDemoUsingAsyncOperation has a bug where it fails to call
// AsyncOperation.OperationCompleted(). Do that for it. If we don’t,
// the AsyncContext will never exit because there are outstanding unfinished
// asynchronous operations.
((AsyncOperation)typeof(AsyncDemoUsingAsyncOperations).GetField("asyncOp", BindingFlags.NonPublic|BindingFlags.Instance).GetValue(demoOperation)).OperationCompleted();
Console.WriteLine("Stopped");
// Start the next task.
startNextTask();
};
demoOperation.Start();
});
}
// Start the first one.
startNextTask();
// AsyncContext requires us to return a Task because that is its
// normal use case.
return Nito.AsyncEx.TaskConstants.Completed;
}
}
With output:
Starting SynchronizationContext
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
Started
Received number 1
Received number 2
Received number 3
Received number 4
Stopped
SynchronizationContext finished
Note that in my example code I work around a bug in AsyncDemoUsingAsyncOperations which you should probably fix: when your operation stops, you never call AsyncOperation.OperationCompleted or AsyncOperation.PostOperationCompleted. This causes AsyncContext.Run() to hang forever because it is waiting for the outstanding operations to complete. You should make sure that your asynchronous operations complete—even in error cases. Otherwise you might run into similar issues elsewhere.
Also, my demo code, to imitate the output you showed in the winforms and console example, waits for each operation to finish before starting the next one. That kind of defeats the point of asynchronous coding. You can probably tell that my code could be greatly simplified by starting all four tasks at once. Each individual task would receive its callbacks in the correct order, but they would all make progress concurrently.
Recommendation
Because of how AsyncOperation seems to work and how it is intended to be used, it is the responsibility of the caller of an asynchronous API that uses this pattern to decide if it wants to receive events in order or not. If you are going to use AsyncOperation, you should document that the asynchronous events will only be received in order by the caller if the caller has a synchronization context that enforces serialization and suggest that the caller call your API on either a UI thread or in something like AsyncContext.Run(). If you try to use synchronization primitives and whatnot inside of the delegate you call with AsyncOperation.Post(), you could end up putting threadpool threads in a sleeping state which is a bad thing when considering performance and is completely redundant/wasteful when the caller of your API has properly set up a synchronization context already. This also enables the caller to decide that, if it is fine with receiving things out of order, that it is willing to process events concurrently and out of order. That may even enable speedup depending on what you’re doing. Or you might even decide to put something like a sequence number in your NewNumberEventArgs in case the caller wants both concurrency and still needs to be able to assemble the events into order at some point.
Lets say I have a component called Tasking (that I cannot modify) which exposes a method “DoTask” that does some possibly lengthy calculations and returns the result in via an event TaskCompleted. Normally this is called in a windows form that the user closes after she gets the results.
In my particular scenario I need to associate some data (a database record) with the data returned in TaskCompleted and use that to update the database record.
I’ve investigated the use of AutoResetEvent to notify when the event is handled. The problem with that is AutoResetEvent.WaitOne() will block and the event handler will never get called. Normally AutoResetEvents is called be a separate thread, so I guess that means that the event handler is on the same thread as the method that calls.
Essentially I want to turn an asynchronous call, where the results are returned via an event, into a synchronous call (ie call DoSyncTask from another class) by blocking until the event is handled and the results placed in a location accessible to both the event handler and the method that called the method that started the async call.
public class SyncTask
{
TaskCompletedEventArgs data;
AutoResetEvent taskDone;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
taskDone.WaitOne(); // but something more like Application.DoEvents(); in WinForms.
taskDone.Reset();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
taskDone.Set(); //or some other mechanism to signal to DoSyncTask that the work is complete.
}
}
In a Windows App the following works correctly.
public class SyncTask
{
TaskCompletedEventArgs data;
public SyncTask()
{
taskDone = new AutoResetEvent(false);
}
public string DoSyncTask(int latitude, int longitude)
{
Task t = new Task();
t.Completed = new TaskCompletedEventHandler(TaskCompleted);
t.DoTask(latitude, longitude);
while (data == null) Application.DoEvents();
return data.Street;
}
private void TaskCompleted(object sender, TaskCompletedEventArgs e)
{
data = e;
}
}
I just need to replicate that behaviour in a window service, where Application.Run isn’t called and the ApplicationContext object isn’t available.
I've had some trouble lately with making asynchronous calls and events at threads and returning them to the main thread.
I used SynchronizationContext to keep track of things. The (pseudo)code below shows what is working for me at the moment.
SynchronizationContext context;
void start()
{
//First store the current context
//to call back to it later
context = SynchronizationContext.Current;
//Start a thread and make it call
//the async method, for example:
Proxy.BeginCodeLookup(aVariable,
new AsyncCallback(LookupResult),
AsyncState);
//Now continue with what you were doing
//and let the lookup finish
}
void LookupResult(IAsyncResult result)
{
//when the async function is finished
//this method is called. It's on
//the same thread as the the caller,
//BeginCodeLookup in this case.
result.AsyncWaitHandle.WaitOne();
var LookupResult= Proxy.EndCodeLookup(result);
//The SynchronizationContext.Send method
//performs a callback to the thread of the
//context, in this case the main thread
context.Send(new SendOrPostCallback(OnLookupCompleted),
result.AsyncState);
}
void OnLookupCompleted(object state)
{
//now this code will be executed on the
//main thread.
}
I hope this helps, as it fixed the problem for me.
Maybe you could get DoSyncTask to start a timer object that checks for the value of your data variable at some appropriate interval. Once data has a value, you could then have another event fire to tell you that data now has a value (and shut the timer off of course).
Pretty ugly hack, but it could work... in theory.
Sorry, that's the best I can come up with half asleep. Time for bed...
I worked out a solution to the async to sync problem, at least using all .NET classes.
Link
It still doesn't work with COM. I suspect because of STA threading. The Event raised by the .NET component that hosts the COM OCX is never handled by my worker thread, so I get a deadlock on WaitOne().
someone else may appreciate the solution though :)
If Task is a WinForms component, it might be very aware of threading issues and Invoke the event handler on the main thread -- which seems to be what you're seeing.
So, it might be that it relies on a message pump happening or something. Application.Run has overloads that are for non-GUI apps. You might consider getting a thread to startup and pump to see if that fixes the issue.
I'd also recommend using Reflector to get a look at the source code of the component to figure out what it's doing.
You've almost got it. You need the DoTask method to run on a different thread so the WaitOne call won't prevent work from being done. Something like this:
Action<int, int> doTaskAction = t.DoTask;
doTaskAction.BeginInvoke(latitude, longitude, cb => doTaskAction.EndInvoke(cb), null);
taskDone.WaitOne();
My comment on Scott W's answer seems a little cryptic after I re-read it. So let me be more explicit:
while( !done )
{
taskDone.WaitOne( 200 );
Application.DoEvents();
}
The WaitOne( 200 ) will cause it to return control to your UI thread 5 times per second (you can adjust this as you wish). The DoEvents() call will flush the windows event queue (the one that handles all windows event handling like painting, etc.). Add two members to your class (one bool flag "done" in this example, and one return data "street" in your example).
That is the simplest way to get what you want done. (I have very similar code in an app of my own, so I know it works)
Your code is almost right... I just changed
t.DoTask(latitude, longitude);
for
new Thread(() => t.DoTask(latitude, longitude)).Start();
TaskCompleted will be executed in the same thread as DoTask does. This should work.