See the following code:
var obs = Observable.Start(() => LongRunningMethodToRetrieveData());
obs.Subscribe(x => MethodThatMustBeOnUIThread(x));
If I am certain that these 2 lines of code are executed on the UI thread, is it necessary to first call ObserveOn(SynchronizationContext.Current)? Or similarly, do I need to check InvokeRequired inside of MethodThatMustBeOnUIThread?
Basically, am I guaranteed with those 2 lines of code that the 'OnNext' will be called on the thread that is creating the subscription?
Thanks.
Edit: Well, I tried in the debugger and 'MethodThatMustBeOnUIThread' is indeed being called from a background thread. Why is this? My assumption now is that the observing happens by default on the thread that the asynchronous method is run on.
You need to get familiar with the default scheduler used by the various Rx methods.
Methods like Observable.Generate do run on the thread that subscribes to the observable.
On the other hand, the Observable.Start method's purpose is to asynchronously call the lamdba action when the observable is subscribed to. It wouldn't be asynchronous if it happened on the UI-thread. So in this case it uses the ThreadPool scheduler.
This can be seen by using Reflector.NET:
public static IObservable<TSource> Start<TSource>(Func<TSource> function)
{
if (function == null)
{
throw new ArgumentNullException("function");
}
return function.ToAsync<TSource>()();
}
public static Func<IObservable<TResult>> ToAsync<TResult>(
this Func<TResult> function)
{
if (function == null)
{
throw new ArgumentNullException("function");
}
return function.ToAsync<TResult>(Scheduler.ThreadPool);
}
So, knowing the scheduler used you must use a form of ObserveOn before calling Subscribe if you want the subscription to run on the UI-thread.
Also, since you are using Rx, I wouldn't use InvokeRequired - that's just mixing asynchronous coding models. Rx has everything you need to play with threads nicely.
Related
We are calling WCF services asyncronously.
public partial class ServiceClient : System.ServiceModel.ClientBase<MyService>, MyService
{
......
}
ServiceClient _serviceclient;
void Getproducts(string filter, string augument, EventHandler<GetCompletedEventArgs> callback)
{
_serviceclient.GetAsyncGetproducts(filter, argument, callback);
}
I want to the Getproducts function to be synchronous. What is the best way to achieve this like the following
void Getproducts(string filter, string augument, EventHandler<GetCompletedEventArgs> callback)
{
_serviceclient.GetAsyncGetproducts(filter, argument, callback);
//wait until callback comes back and return
}
EDIT: The proxy is providing any synchronous calls
You cannot make synchronous networking requests in Silverlight from the UI thread. There's no going around that. Even if you try to trick the asynchronous methods into behaving synchronously, it will not work. That's because if that were possible, the UI thread would be blocked, and the application would appear to be frozen. This happens because the responses to networking requests in SL are always delivered to the UI thread; if you wait for it on the UI thread itself, then you create a deadlock.
You essentially have two options: the preferred one is to actually go the asynchronous route. It's hard at first, if you're only used to synchronous programming, but it's a very valuable skill to have. The other option is to make the call on a background thread. I've tried it and it works, and some people have blogged about it, so you can try it as well. But AFAIK it's not officially supported.
Rather than just passing the callback parameter as the callback you'll want to assign your own callback that executes that method in addition to doing something else. You effectively just need to trigger an event of some sort. I have demonstrated one way using tasks, but you could just as easily use an auto reset event or one of any number of other synchronization methods.
void Getproducts(string filter, string augument, EventHandler<GetCompletedEventArgs> callback)
{
var tcs = new TaskCompletionSource<bool>();
_serviceclient.GetAsyncGetproducts(filter, argument, args =>
{
callback(args);
tcs.SetResult(true);
});
tcs.Task.Wait();
}
Suppose you are invoking methods asynchronously onto the UI thread.
With
UIDispatcher.BeginInvoke( new Action(_insert), DispatcherPriority.Normal, new object[] { } )
you are doing the invocation. From now the runtime environment decides when to execute the method whereas the program continues its 'normal' path of execution.
I am now wondering whether there are any mechanisms to synchronize these asynchronously executed methods when they are returning ? It seems that there are pretty much the same issues as when using multiple threads.
But is a returning method that has been invoked asynchronously before considered to be a thread ? It don't seem so because usual synchronizing efforts like
lock (someObject) { //... }
or using dedicated locks seem not to work.
Appendix:
My actual situation where this issue appears is as follows:
The asynchronously invoked method calls as its last statement a returnmethod of a static class. Inside this return method a commonly used resource (a List) has to be synchronized. Consider the following (overview-like) code-snipped to exemplify:
// A simple method that gets invoked asynchronously
public void _insert () {
// do some code
StaticClass.Returned();
}
public static StaticClass {
//...
public static void Returned () {
// use a shared resource !
}
}
Either use the .NET's asynchronous pattern, a BackgroundWorker, or a ManualResetEvent
http://msdn.microsoft.com/en-us/library/ms228969.aspx
Is there any good practice (pattern) in turning asynchronous calls into synchronous?
I have a third party library who's methods are all asynchronos, to get result of almoust any method you must listen to an event, which will bring some context with it.
basically it looks like:
service.BeginSomething(...);
service.OnBeginSomethingCompleted += ;
what I need is to execute some code after BeginSomething when it is really complete (thus after OnBeginSomethingCompleted is triggered). It is very inconvinient to handle the response in the event.
The only way I could think of is running a Thread.Sleep loop and wait till some field on the form is updated, but it doesn't look like very elegant sollution.
I'm using .net 4.0.
You could subclass the main class and provide a synchronous version of the operation. If subclassing is not an option you could create an extension method. Here is how things might look.
public class Subclass : BaseClass
{
public void Something()
{
using (var complete = new ManualResetEventSlim(false))
{
EventHandler handler = (sender, args) => { complete.Set(); };
base.OnBeginSomethingCompleted += handler;
try
{
base.BeginSomething();
complete.Wait();
}
finally
{
base.OnBeginSomethingCompleted -= handler;
}
}
}
}
Update:
One thing I should have pointed out is that this could be problematic in some cases. Consider this example.
var x = new Subclass();
x.BeginSomething();
x.Something();
It should be obvious that the handler in Something could receive the OnBeginSomethingCompleted event from the previous call to BeginSomething. Make sure you guard against this somehow.
Use a ManualResetEvent. In your sync wrapper create it, then pass it to the service.BeginSomething() call as part of the state object. Immediately after the call, WaitOne() on it, this will block.
In the service.OnBeginSomethingCompleted event extract it from the state object and set it, this will unblock the sync caller.
As other said, if possible you should try to make your own code async. If that won't work, does your third-party library support the standard BeginXXX, EndXXX async pattern? If so, then using the TPL would make things easy for you. Your code will look something like this:
using System.Threading.Tasks;
...
var task = Task<TResult>.Factory.FromAsync(
service.BeginSomething, service.EndSomething, arg1, arg2, ..., null);
task.Wait();
var result = task.Result;
The specific overload you'll want to use will depend on how many parameters you need to pass. You can see the list here.
If BeginSomething() returns an IAsyncResult (like a delegate's .BeginInvoke would do), you can get the WaitHandle from that:
service.OnBeginSomethingCompleted += ;
var asyncResult = service.BeginSomething();
asyncResult.AsyncWaitHandle.WaitOne(); // Blocks until process is complete
By the way, by assigning the event handler after starting the async process, you are introducing a race condition where the async call may complete before the event is registered, causing it to never fire.
You might want to look at Reactive Extensions
With Rx you can wrap that into an 'event' basically - the do something like someClass.SomeEvent.Subscribe(d=>...) to subscribe using usually some lambda expression to handle what you need. Also use ObserveOn to handle it on the GUI thread (see the details, this is just a hint).
Other option is to use async await (which is now available for use with VS 2010).
hope this helps
NOTE: Rx have a native support for async methods and turning them into Rx events with pretty much just one call. Take a look at Observable.FromAsyncPattern FromAsyncPattern
The general trend of modern software development (on Windows platform too) is to run, what is possible asynchroniously.
Actually from Windows8 software design guidelines, if the code runs more then 50ms, it has to be asynchronious.
So I would not suggest to block the thread, but instead benefit from that library and provide to the user with some nice looking animation saying "wait, responce comming", or something like this, or some progress bar.
In short, do not block thread, notify a user about what is going on in app and leave it async.
This solution is similar to Brian Gideon's, but I think a little bit cleaner for what you're trying to do. It uses the Monitor object to cause the calling thread to wait until the Completed event is triggered.
public class SomeClass : BaseClass
{
public void ExecuteSomethingAndWaitTillDone()
{
// Set up the handler to signal when we're done
service.OnBeginSomethingCompleted += OnCompleted;
// Invoke the asynchronous method.
service.BeginSomething(...);
// Now wait until the event occurs
lock (_synchRoot)
{
// This waits until Monitor.Pulse is called
Monitor.Wait(_synchRoot);
}
}
// This handler is called when BeginSomething completes
private void OnCompleted(object source, ...)
{
// Signal to the original thread that it can continue
lock (_synchRoot)
{
// This lets execution continue on the original thread
Monitor.Pulse(_synchRoot);
}
}
private readonly Object _synchRoot = new Object();
}
I am work my way through different open source projects to get a feel for how people approach the same problem in different ways. This time it's Event Aggregators, specifically Caliburn.Micro's one.
I notice that Rob said that if no thread is supplied that the EA will marshal to the UI thread. The line specifically is:
public static Action<System.Action>
DefaultPublicationThreadMarshaller = action => action();
and then further on:
marshal(() =>
{
*SNIP*
});
What I don't understand his how can you say this will be called on the UI thread, are all actions called on the UI thread unless you specify one that is not? (You can specify which action is called btw, the line above is just if no action is supplied).
Action can be invoked either in the thread that calls it:
Action a = () => Foo();
a.Invoke();
Or it can be invoked asynchronously
Action a = () => Foo();
a.BeginInvoke();
If the event aggregator is configured to use a synchronous call then it is possible that the event gets handled in the UI thread. However it is very unlikely, and usually an event aggregator uses asynchronous execution and the action is executed in a thread pool.
In the code in question there will be a place, where it (internally and not included here) calls either Invoke or BeginInvoke on the action, this is where the difference is.
N.B. This answer is not specific to any particular event aggregator.
The Task Parallel Library is great and I've used it a lot in the past months. However, there's something really bothering me: the fact that TaskScheduler.Current is the default task scheduler, not TaskScheduler.Default. This is absolutely not obvious at first glance in the documentation nor samples.
Current can lead to subtle bugs since its behavior is changing depending on whether you're inside another task. Which can't be determined easily.
Suppose I am writting a library of asynchronous methods, using the standard async pattern based on events to signal completion on the original synchronisation context, in the exact same way XxxAsync methods do in the .NET Framework (eg DownloadFileAsync). I decide to use the Task Parallel Library for implementation because it's really easy to implement this behavior with the following code:
public class MyLibrary
{
public event EventHandler SomeOperationCompleted;
private void OnSomeOperationCompleted()
{
SomeOperationCompleted?.Invoke(this, EventArgs.Empty);
}
public void DoSomeOperationAsync()
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(1000); // simulate a long operation
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(t =>
{
OnSomeOperationCompleted(); // trigger the event
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
So far, everything works well. Now, let's make a call to this library on a button click in a WPF or WinForms application:
private void Button_OnClick(object sender, EventArgs args)
{
var myLibrary = new MyLibrary();
myLibrary.SomeOperationCompleted += (s, e) => DoSomethingElse();
myLibrary.DoSomeOperationAsync(); // call that triggers the event asynchronously
}
private void DoSomethingElse() // the event handler
{
//...
Task.Factory.StartNew(() => Thread.Sleep(5000)); // simulate a long operation
//...
}
Here, the person writing the library call chose to start a new Task when the operation completes. Nothing unusual. He or she follows examples found everywhere on the web and simply use Task.Factory.StartNew without specifying the TaskScheduler (and there is no easy overload to specify it at the second parameter). The DoSomethingElse method works fine when called alone, but as soon at it's invoked by the event, the UI freezes since TaskFactory.Current will reuse the synchronization context task scheduler from my library continuation.
Finding out this could take some time, especially if the second task call is buried down in some complex call stack. Of course, the fix here is simple once you know how everything works: always specify TaskScheduler.Default for any operation you're expecting to be running on the thread pool. However, maybe the second task is started by another external library, not knowing about this behavior and naively using StartNew without a specific scheduler. I'm expecting this case to be quite common.
After wrapping my head around it, I can't understand the choice of the team writing the TPL to use TaskScheduler.Current instead of TaskScheduler.Default as the default:
It's not obvious at all, Default is not the default! And the documentation is seriously lacking.
The real task scheduler used by Current depends of the call stack! It's hard to maintain invariants with this behavior.
It's cumbersome to specify the task scheduler with StartNew since you have to specify the task creation options and cancellation token first, leading to long, less readable lines. This can be alleviated by writing an extension method or creating a TaskFactory that uses Default.
Capturing the call stack has additional performance costs.
When I really want a task to be dependent on another parent running task, I prefer to specify it explicitly to ease code reading rather than rely on call stack magic.
I know this question may sound quite subjective, but I can't find a good objective argument as to why this behavior is as it. I'm sure I'm missing something here: that's why I'm turning to you.
I think the current behavior makes sense. If I create my own task scheduler, and start some task that starts other tasks, I probably want all the tasks to use the scheduler I created.
I agree that it's odd that sometimes starting a task from the UI thread uses the default scheduler and sometimes not. But I don't know how would I make this better if I was designing it.
Regarding your specific problems:
I think the easiest way to start a new task on a specified scheduler is new Task(lambda).Start(scheduler). This has the disadvantage that you have to specify type argument if the task returns something. TaskFactory.Create can infer the type for you.
You can use Dispatcher.Invoke() instead of using TaskScheduler.FromCurrentSynchronizationContext().
[EDIT]
The following only addresses the problem with the scheduler used by Task.Factory.StartNew.
However, Task.ContinueWith has a hardcoded TaskScheduler.Current.
[/EDIT]
First, there is an easy solution available - see the bottom of this post.
The reason behind this problem is simple: There is not only a default task scheduler (TaskScheduler.Default) but also a default task scheduler for a TaskFactory (TaskFactory.Scheduler).
This default scheduler can be specified in the constructor of the TaskFactory when it's created.
However, the TaskFactory behind Task.Factory is created as follows:
s_factory = new TaskFactory();
As you can see, no TaskScheduler is specified; null is used for the default constructor - better would be TaskScheduler.Default (the documentation states that "Current" is used which has the same consequences).
This again leads to the implementation of TaskFactory.DefaultScheduler (a private member):
private TaskScheduler DefaultScheduler
{
get
{
if (m_defaultScheduler == null) return TaskScheduler.Current;
else return m_defaultScheduler;
}
}
Here you should see be able to recognize the reason for this behaviour: As Task.Factory has no default task scheduler, the current one will be used.
So why don't we run into NullReferenceExceptions then, when no Task is currently executing (i.e. we have no current TaskScheduler)?
The reason is simple:
public static TaskScheduler Current
{
get
{
Task internalCurrent = Task.InternalCurrent;
if (internalCurrent != null)
{
return internalCurrent.ExecutingTaskScheduler;
}
return Default;
}
}
TaskScheduler.Current defaults to TaskScheduler.Default.
I would call this a very unfortunate implementation.
However, there is an easy fix available: We can simply set the default TaskScheduler of Task.Factory to TaskScheduler.Default
TaskFactory factory = Task.Factory;
factory.GetType().InvokeMember("m_defaultScheduler", BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly, null, factory, new object[] { TaskScheduler.Default });
I hope I could help with my response although it's quite late :-)
Instead of Task.Factory.StartNew()
consider using: Task.Run()
This will always execute on a thread pool thread. I just had the same problem described in the question and I think that is a good way of handling this.
See this blog entry:
http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
It's not obvious at all, Default is not the default! And the documentation is seriously lacking.
Default is the default, but it's not always the Current.
As others have already answered, if you want a task to run on the thread pool, you need to explicitly set the Current scheduler by passing the Default scheduler into either the TaskFactory or the StartNew method.
Since your question involved a library though, I think the answer is that you should not do anything that will change the Current scheduler that's seen by code outside your library. That means that you should not use TaskScheduler.FromCurrentSynchronizationContext() when you raise the SomeOperationCompleted event. Instead, do something like this:
public void DoSomeOperationAsync() {
var context = SynchronizationContext.Current;
Task.Factory
.StartNew(() => Thread.Sleep(1000) /* simulate a long operation */)
.ContinueWith(t => {
context.Post(_ => OnSomeOperationCompleted(), null);
});
}
I don't even think you need to explicitly start your task on the Default scheduler - let the caller determine the Current scheduler if they want to.
I've just spent hours trying to debug a weird issue where my task was scheduled on the UI thread, even though I didn't specify it to. It turned out the problem was exactly what your sample code demonstrated: A task continuation was scheduled on the UI thread, and somewhere in that continuation, a new task was started which then got scheduled on the UI thread, because the currently executing task had a specific TaskScheduler set.
Luckily, it's all code I own, so I can fix it by making sure my code specify TaskScheduler.Default when starting new tasks, but if you aren't so lucky, my suggestion would be to use Dispatcher.BeginInvoke instead of using the UI scheduler.
So, instead of:
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var task = Task.Factory.StartNew(() => Thread.Sleep(5000));
task.ContinueWith((t) => UpdateUI(), uiScheduler);
Try:
var uiDispatcher = Dispatcher.CurrentDispatcher;
var task = Task.Factory.StartNew(() => Thread.Sleep(5000));
task.ContinueWith((t) => uiDispatcher.BeginInvoke(new Action(() => UpdateUI())));
It's a bit less readable though.