I have a multi-threaded UI application that starts numerous background threads. A lot of these threads execute code that looks as follows:
public void Update(){
if(Dispatcher.HasShutdownStarted()) return;
Dispatcher.Invoke(()=>{...});
...
}
Then I sometimes may have a thread execute the following code
pubic void Shutdown(){
if(Dispatcher.HasShutdownStarted()) return;
Dispatcher.InvokeShutdown();
}
The problem is that sometimes one thread executes Dispatcher.InvokeShutdown() AFTER another thread executed Dispatcher.HasShutdwonStarted() but before it got to Dispatcher.Invoke(()=>{...}). Which means, that there will be a thread trying to execute a lambda on the Dispatcher once the Dispatcher has begun to shut down. And that's when I get exceptions. What is the best solution to this?
The problem you face is that the HasShutdownStarted is checked, before the code inside the Invoke is executed (because it's queued on the dispatcher)
I think a better way is to check it inside the invoke, this way you don't need any locks.
public void Update(){
Dispatcher.Invoke(()=>
{
if(Dispatcher.HasShutdownStarted()) return;
...
});
}
With the help of others I managed to come up with the following solution to my problem and thought I'd share it. Calling Dispatcher.Invoke(...) after Dispatcher.InvokeShutdown() will always lead to a TaskCancelationException being thrown (as far as I can tell). Thus, checking Dispatcher.HasShutdownStarted inside of the Invoke method will not work.
What I did was create an application global CancellationToken by creating a static CancellationTokenSource. I now invoke the Dispatcher as follows:
Dispatcher.Invoke(()=>{...}, DispatcherPriority.Send, GlobalMembers.CancellationTokenSource.Token);
Then, when I wish to invoke shutdown on my dispatcher, I do the following:
GlobalMembers.CancellationTokenSource.Cancel();
Dispatcher.InvokeShutdown();
If by any chance I try to run Dispatcher.Invoke(()=>{...}, DispatcherPriority.Send, GlobalMembers.CancellationTokenSource.Token) after cancelling the global token and after invoking Dispatcher.InvokeShutdown(), nothing happens as the token is already cancelled and thus the action is not run.
Related
I would like to stop a method until a custom delegate provides a callback from one method to a listener in another in Xamarin.Android, but I am having a lot of trouble understanding the implementation of such a listener.
I have only tried to understand how this could be done, but I'm stuck on how the delegate would be constructed and called.
Let's say that I want this MainActivity method to stop
public async override void OnWindowFocusChanged(bool hasFocus)
{
base.OnWindowFocusChanged(hasFocus);
//how can I create a listener to stop this method until callback from OnPause?
//await a delegate task?
}
and await another method inside a Fragment:
public override void OnResume()
{
base.OnResume();
//I'd like to implement a delegate here to notify the OnWindowFocusChanged that OnResume method has been invoked
//what would be the construction of such?
}
How could I do that?
From my research, I believe I would need to create a delegate task, and then await it's return in OnWindowFocusChanged. However, I am confused about the implementation of such a solution. If anyone could provide even a very basic pseudo-code example, it would help me out a lot.
EDIT: I changed OnPause to OnResume because that's more useful for understanding what I'm trying to do. The below answer references OnPause, but those two are extremely similar methods anyway.
Here is an example that almost does what I'm trying to do; except instead of starting my method when OnResume is invoked, OnWindowFocusChanged stops for 10000ms. So basically, I'd like to replace the timer with a custom delegate (similar to an event) task that returns when Fragment.OnResume is invoked.
public async override void OnWindowFocusChanged(bool hasFocus)
{
base.OnWindowFocusChanged(hasFocus);
//we won't pass this line for 10000ms; how to replace with Task return?
await WaitHere();
}
async Task WaitHere()
{
System.Threading.Thread.Sleep(10000);
}
You could try Task.Run method like:
await Task.Run(() => OnPause());
This would basically create a new thread or use the one you are on and schedule everything after this line as a continuation. So yes, the method would kinda stop, but unless you are on some GUI thread (not to block) or you run some IO task this is unnecessary.
I do not really understand what you are trying to achieve, but you might try to create new OnPauseAsync method that would return Task to get some result from the method when it finishes. This way you would get sequential like mechanism that doesn't block.
If you want to run those methods truly in parallel, but stop execution of OnWindowFocusChanged unitl something hapens in OnPause you should use bare Threads and some synchronization primitives like Mutex or Barrier. Then you would be able to make "main" thread wait until something happens (but it would block! beware). About those fellas you can read more here : LINK_WITH_FOCUS_ON_BARRIER
I am not really sure I got your intentions right, but I hope it helps somehow in the end.
To review:
if you just want to wait for the completion of OnPause and it does only CPU heavy things and you are not on UI thread - do not do anything as there is no profit in using threads etc.
if onPause does some IO heavy things you can use:
Tasks - potentially executed on one thread and doesn't block, control is returned to OnWindowFocusChanged AFTER onPause finishes completely.
Threads - if you want to run some parallel (two threads guaranteed) computations and wait for onPause to signal AT SOME POINT of execution to its caller that it might proceed, you can use e.g Barrier - but beware as this is the most complex solution from programmers perspective and it blocks if you are on UI thread.
I'm writing a application with a critical region.
And I decide to use AutoResetEvent to achieve mutual exclusion.
Here's the code
public class MyViewModel
{
private AutoResetEvent lock = new AutoResetEvent(true);
private aync Task CriticalRegion()
{
Dosomething();
}
public async Task Button_Click()
{
Debug.WriteLine("Entering Button_Click");
lock.WaitOne();
try
{
await CriticalRegion();
}
finally
{
lock.Set();
Debug.WriteLine("Leaving Button_Click");
}
}
}
I have a button whose click event calls the Button_Click() method
It works normally. But, if I'm quick enough to click the button for another time before the first call to Button_Click() completes, the whole app stops responding.
In the Debug window I find something like this
Entering Button_Click
Entering Button_Click
Looks like the method never completes.
I struggled a bit and find that if I change lock.WaitOne(); to
if (!sync.WaitOne(TimeSpan.FromSeconds(1)))
{
return;
}
In this case my app is able to avoid the deadlock,but I don't know why it works.
I only know about the IPC from my OS course and the async and await pattern in C#, and I'm not so familiar with the thread in .Net world.
I really want to understand what's really going on behind the scenes.
Thanks for any replys ;)
You have a deadlock because WaitOne is blocking the main thread (button click handler is executed on the main thread), while you haven't called ConfigureAwait(false) when calling await, which means that it tries to run the code which is after await on the main thread, even if it's blocked, which would causes a deadlock.
I suggest reading this post for a thorougher explanation of the dead lock situation.
For your code, I would suggest putting the lock deeper, probably within the async Task, and trying to use a more suitable pattern for locking, preferably, the lock statement, because using Event objects is awkward for mutual exclusion, as Hans stated in the comment.
AutoResetEvent.WaitOne() will block infinitely until you call AutoResetEvent.Set(), which you never seem to do except for after the WaitOne() call.
Quoting the AutoResetEvent.WaitOne() documentation:
Blocks the current thread until the current WaitHandle receives a signal.
I have a function (Shutdown()) which is used to terminate my windows form (does some clean up and call this.close() at the end).
In my application I have threads of execution
The UI
A background worker
A timer
Each one of these can call Shutdown(), either by the user pressing a button (UI), the timer expiring (timer), or the background worker completing his task. This leads me to a worry that if the timing is really bad I can have more then one thread calling Shutdown() at the same time.
So how can I ensure that only the first one that calls it will execute it? Any subsequent calls should just be ignored as the call will end in terminating the application anyways.
It's not really clear from your question what the difficulty is. What have you tried? What trouble did you run into?
The obvious, trivial implementation would be something like this:
private readonly object _lock = new object();
private bool _shuttingDown;
public void Shutdown()
{
lock (_lock)
{
if (_shuttingDown) return;
_shuttingDown = true;
}
// do work here...
}
Is there some reason that doesn't work in your scenario? If so, please provide a good, minimal, complete code example that shows clearly what you've tried, a describe precisely what that code does and how that's different from what you want it to do.
I'm a bit of a newbie at this but I am trying to get the UI on a Reversi game to run on a different thread to the move selection part but I am having some trouble calling the thread on the button click
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
ReversiT.Invoke();
}
public void ReversiT() {...}
If you're trying to create a new thread, you can do something like this:
Thread thread = new Thread(ReversiT);
thread.Start();
Invoke is used for a different purpose though. It is used to run a method on a specific thread (for instance, if you run a piece of code on a separate thread but want to make UI changes, you will want to use Invoke to make those changes on the UI thread)
I would create a BackgroundWorker to handle everything for me, setting it's DoWork event to call your move method (making sure that your move method doesn't touch the UI, or if it has to, invoking the controls on the UI thread).
I'd also set up a method to update the UI on the BackgroundWorker's RunWorkerCompleted event.
Now on your button click event above, call the BGW's RunWorkerAsync() method.
You can not invoke a method like that. You can only invoke delegates. Also, calling Invoke doesn't spawn a new thread.
You can read this tutorial about delegates, and this one about threads. Also, your question leaves much space for discussion:
What do you expect from using threads?
Have you considered different options for doing background work?
etc.
Use following
this.Invoke(ReversiT);
I think you need to think about that you are actually trying to achieve here. Running code on a separate thread in a UI is a technique used to stop the UI from hanging. However, some tasks simply have to occur on the UI thread and so can't be run from another thread.
You need to break your logic out such that you can identify which parts need to run on the UI thread (anything that interacts with a control on your UI) and thus anything that can run on a separate thread.
You would end up with code like (as an example):
private void playerMoveOKButton_Click(object sender, EventArgs e)
{
//thread is merely used as an example
//you could also use a BackgroundWorker or a task
var thread = new Thread(NonUiLogic);
thread.Start();
}
private void NonUiLogic()
{
...
//execute logic that doesn't touch UI
...
BeginInvoke(ReversiT);
}
public void ReversiT() {...}
Once you have been through that exercise you may find that there is actually very little that can happen outside of the UI thread and so you really have nothing to gain from using threads.
I am working on a project of my company in which they used Dispatcher.Invoke() in many places.If I am using BeginInvoke instead of Invoke then the Synchronisation between threads working fine but in case of Invoke the application is freezing and even not entering the execution to the delegate method also. Does anybody have any idea why it is happening like this?
Any answer will be appreciated.
Sample Code for Invoke used in the Project:
Dispatcher.Invoke(DispatcherPriority.Send,
new DelegateMethod(MethodtoExecute));
private delegate void DelegateMethod();
void MethodtoExecute()
{
try
{
}
catch (Exception /*ex*/)
{
}
finally
{
}
}
Dispatcher.Invoke executes synchronously on the same thread as your application, so whatever you invoke is able to block the main application thread. Dispatcher.BeginInvoke executes asynchronously, so it doesn't tie up the main application thread while executing.
Since you are using DispatcherPriority.Send, which is the highest dispatcher priority level, whatever you are invoking gets run before anything else, including rendering the screen or listening for events. I'd recommend switching that to DispatcherPriority.Background, which runs at a lower priority than Render and Input. See this page for a list of the DispatcherPriority levels and their execution order
I'd highly recommend you look at the answer posted here