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
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 have a scenario where I have a main thread which uses a whole bunch of other threads from the threadpool that do some work.
In the main thread I am using an object which is not thread safe (3rd party component, so it's not feasible to change this). The threadpool threads need to invoke methods on this non-thread-safe object. In the main thread I have an object representing the thread on which the 3rd party component is declared:
private ThirdPartyComponent third_party_component;
private Thread mainThread;
In the initialization method on the main thread, I save a reference to the "safe" thread for accessing the 3rd party component:
mainThread = Thread.CurrentThread;
What I am trying to do is create some method which will "dispatch" the invocation of the 3rd party component to the correct thread, something like this:
private void DoTheWork()
{
if(Thread.CurrentThread != mainThread)
{
mainThread.Invoke( () => { third_party_component.DoItThreadSafe(); } );
}
}
I have regularly used this pattern for updating UI code on the main thread using Control.Invoke, but the Thread object which I have saved (mainThread) does not have an Invoke method.
Is there something special about the UI thread that allows this to take place? Or am I missing something on the Thread object? What is the best way to get DoTheWork() to run on the main thread?
(Edit: FWIW in this application mainThread will be the main Winforms GUI thread, but I am hoping to find a solution which works on any thread and does not rely on the main thread being the GUI thread.)
Normally when talking about non-threadsafe objects it simply means it cannot be called by multiple threads concurrently. If so it should be safe to simply lock the non-threadsafe object and call it from whatever thread you are using.
It is possible to write objects that can only be called by the thread that created the object thread. If so perhaps something like this could work:
public class TaskManager<T>
{
private readonly Func<T> constructor;
private BlockingCollection<Action<T>> queue = new BlockingCollection<Action<T>>(new ConcurrentQueue<Action<T>>());
public TaskManager(Func<T> constructor)
{
this.constructor = constructor;
var thread = new Thread(ThreadMain);
thread.Start();
}
private void ThreadMain()
{
var obj = constructor();
foreach(var action in queue.GetConsumingEnumerable())
{
action(obj);
}
}
public void ScheduleWork(Action<T> work) => queue.Add(work);
public void CompleteAdding() => queue.CompleteAdding();
}
Disclaimer: Not tested, no error handling, no handling of disposable objects etc.
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.
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.
I have a class Communicator that works in a background thread receiving data on a TCP port.
The Communicator has an event OnDataReceived which is of a EventHandler<DataReceivedEventArgs> type.
There is another class Consumer that contains a method subscribed to the Communicator.OnDataReceived event.
comm.OnDataReceived += consumer.PresentData;
The Consumer class is created within a Form constructor and then one of its methods is called on another thread. This method is an infinite loop, so it stays in that method during the application execution.
What I'd like to do is for the Communicator.OnDataReceived event to invoke the consumer.PresentData method on consumer's thread.
Is that even nearly possible? And if it is, what kind of mechanisms (sync classes) should I use?
Add this somewhere in your code: (I usually put this in a static helper class called ISynchronizedInvoke so I can call ISynchronizedInvoke.Invoke(...));
public static void Invoke(ISynchronizeInvoke sync, Action action) {
if (!sync.InvokeRequired) {
action();
}
else {
object[] args = new object[] { };
sync.Invoke(action, args);
}
}
Then inside OnDataReceived, you could do:
Invoke(consumer, () => consumer.PresentData());
This invokes 'consumer.PresentData' on 'consumer'.
As for your design issue (consumer references communicator), you could introduce a method inside communicator such as:
class Communicator {
private ISynchronizeInvoke sync;
private Action syncAction;
public void SetSync(ISynchronizeInvoke sync, Action action) {
this.sync = sync;
this.syncAction = action;
}
protected virtual void OnDataReceived(...) {
if (!sync.InvokeRequired) {
syncAction();
}
else {
object[] args = new object[] { };
sync.Invoke(action, args);
}
}
}
This would give you a way to pass in the ISynchronizedInvoke from your consumer class. So you would be creating the ISynchronizedInvoke in the consumer assembly.
class Consumer {
public void Foo() {
communicator.SetSync(this, () => this.PresentData());
}
}
So basically you are creating everything you need to do the invoke, and just passing it in to your communicator. This resolves your necessity to have an instance or reference to consumer in communicator.
Also note that I did not test any of this I am doing this all in theory, but it should work nicely.
Try to use the BackgroundWorker class.
It should be possible. You may create a queue for execution, or look at the Dispatcher object, it's useful (and sometimes mandatory as the only way) to push some methods into the UI Thread, it that helps.
You can get a method to execute on a thread only if the target thread is designed to accept a marshaling operation that transfers the execution of the method from the initiating thread to the target thread.
One way to get this to work is to have your Consumer class implement ISynchronizeInvoke. Then have your Communicator class accept an ISynchronizeInvoke instance that it can use to perform the marshaling operation. Take a look at the System.Timers.Timer class as an example. System.Timers.Timer has the SynchronizingObject property that it can use to marshal the Elapsed event onto the thread hosting the synchronizing object by calling ISynchronizeInvoke.Invoke or ISynchronizeInvoke.BeginInvoke.
The tricky part is how you implement ISynchronizeInvoke on the Consumer class. The worker thread started by that class will have to implement the producer-consumer pattern to be able to process delegates. The BlockingCollection class would make this relatively easy, but there is still quite a learning curve. Give it a shot and post back with a more focused question if you need more help.