I need to get the main thread notified when a worker thread finishes. When I take a delegate and execute it on the other thread when it's finished, it get's executed on that thread, which is not what I want. Neither I can check for it to be finished due to some restrictions I have ('Update' in Unity Editor not called every frame). Are there any other options I have?
You can use async/await..
async void MyFunc()
{
await Task.Run(() => { /* your work in thread */ });
//Your work is finished at this point
}
And as a plus, you can surround it with try-catch block and catch the exceptions that may happen in your work in a smart way.
//This is a helper coroutine
IEnumerable RunOffMainThread(Action toRun, Action callback) {
bool done = false;
new Thread(()=>{
toRun();
done = true;
}).Start();
while (!done)
yield return null;
callback();
}
//This is the method you call to start it
void DoSomethingOffMainThread() {
StartCoroutine(RunOffMainThread(ToRun, OnFinished));
}
//This is the method that does the work
void ToRun() {
//Do something slow here
}
//This is the method that's called when finished
void OnFinished() {
//off main thread code finished, back on main thread now
}
Related
I'm writing some code that is invoked on the UI thread, invokes some code on another thread (not the ThreadPool, but the same thread each time), and then resumes on the UI thread. I'd like some advice on the best async way to do this.
The complexity of the EnsureThread method is because the other thread must be the same thread every time and must be STA with a Dispatcher running on it. This is because I need to use MCI, but do not want it running on the UI thread. See here https://stackoverflow.com/a/32711239/420159.
I create the second thread like so:
private static void EnsureThread()
{
if (eventLoopThread != null)
{
return;
}
lock (eventLoopLock)
{
if (eventLoopThread == null)
{
var lck = new EventWaitHandle(false, EventResetMode.ManualReset);
var t = new Thread(() =>
{
try
{
// create dispatcher and sync context
var d = Dispatcher.CurrentDispatcher;
var context = new DispatcherSynchronizationContext(d);
SynchronizationContext.SetSynchronizationContext(context);
// create taskfactory
eventLoopFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
eventLoopDispatcher = d;
}
finally
{
lck.Set();
}
// run the event loop
Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
lck.WaitOne();
lck.Dispose();
eventLoopThread = t;
}
}
}
and then I call the second thread like so:
async void button_click(...)
{
// do something 1
await eventLoopFactory.StartNew(()=>
{
// do something 2
});
// do something 3
}
Is there a better way to do it?
You don't really need to use a thread factory if you want to run a delegate on a thread of the ThreadPool
just use
await Task.Run(() =>
{
// do something 2
});
That way, you don't need to run your // do something code on an event loop thread, but it will be run on an available thread from the thread pool.
You shouldn't create a second thread yourself. Thread pools are the right tool for that, as it will recycle idle threads in a very efficient way.
Your Button_Click already seems to be doing way too many things, you should first split this method into separate methods.
async void Button_Click(...)
{
await DoSomething1();
await DoSomething2();
await DoSomething3();
}
Now, your other methods will look something like this:
async Task DoSomething1()
{
await Task.Run(() =>
{
...
});
}
This will allow your Button_Click method to asynchronously perform these tasks (in order) and keep your UI responsive.
I have a method:
public void Run()
{
instalProgressPageViewModel.ExecuteButton_Click();
//waiting here
Environment.Exit(0);
}
Method Execute_Click() calls a installers of msi packages. Those installers run in separate threads:
this.uiDispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new InstallationCompleted(this.completeInstallDelegate),
installationState);
where:
this.completeInstallDelegate // method which should be called after the thread is done.
Waiting for function CompleteInstall is crucial as its finalize installation and begins installation next msi package in a list of packages.
In the sample code of method Run app is closed before anything can happen.
I tried putting:
while(true){}
In a place of // waiting here and put breakpoint in CompleteInstall method to check if it will be called but it wasn't hit. App is stucked in infite loop inside while.
What can I do to force my main thread to wait for threads and jump into completeinstall method when its called by delegate?
#Update:
With your suggestions my code looks like this:
there is
public static ManualResetEvent mre // global object initialized in main
and other class is:
public void Run()
{
instalProgressPageViewModel.ExecuteButton_Click();
mre.WaitOne();
Environment.Exit(0);
}
ExecuteButton_Click call this function:
public void StartProcessing()
{
var processor = new Action(this.DoProcessing);
processor.BeginInvoke(null, null);
}
now DoProcessing:
private void DoProcessing()
{
var installationState = this.Execute();
// Schedule the update function in the UI thread.
this.uiDispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new InstallationCompleted(this.completeInstallDelegate),
installationState);
}
and finally completeInstallDelegate
private void CompleteInstall(InstallationState installationState)
{
App.mre.Set();
/*
Some code
*/
this.PostInstallAndNext();
}
If I put break Point at the line App.mre.Set() it is never hit.
and for unknow reason for me the DoProcessing is called after mre.WaitOne(). Does Action and BeginInvoke work out of sync too?
Thanks for updating the question.
It looks like you are never creating an actual new Thread, i.e. you are suspending the main thread and effectively deadlocking your application.
You could create an new Thread here:
public void StartProcessing()
{
var thread = new Thread(() => this.DoProcessing);
thread.Start();
}
You could use the ManualResetEvent class.
Create a ManualResetEvet
ManualResetEvent mre = new ManualResetEvent(false);
In the Main method wait for this event to get signalled.
mre.WaitOne();
In your delegate (when the work is finished), signal the event.
mre.Set();
A simple solution would be to use ManualResetEvent.
You would then have a blocking call to WaitOne, until you call Set from the other thread.
I want to perform series of operations synchronously while closing my MVVM based WPF Application.
Right now I am using Task and Dispatcher.Invoke within the tasks to show the message to the user.
The issue is that when i used Dispatcher.Invoke method in the myfunction function, application gets stuck there. I know this function is working properly when I used these function other than closed event.
So is there any issue of using the Dispatcher.Invoke method in the Close event os the application. How can i solve this?
/// <summary>
/// Main window closing
/// </summary>
private void MainWindowClosing(object args)
{
var task1 = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
myfunction();
}).ContinueWith((cc) => { });
task1.Wait();
}
private void myfunction()
{
//my serries of operation will come here.
System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
{
MessageBox.Show("test");
}));
}
You are creating a Deadlock here. It won't work even when you put the code in button click handler.
REASON
You are creating a task and waiting on task using task1.Wait(). Hence UI dispatcher is waiting for task to complete before it can process any further messages.
At same time you are invoking one operation on UI dispatcher from task that too synchronously here
App.Current.Dispatcher.Invoke(new Action(() =>
{
MessageBox.Show("test");
}));
but since UI dispatcher is still waiting on task to complete, you can't invoke any method synchronously on it. Hence the DEADLOCK (waiting on each other).
Possible Solution
If you want to invoke task synchronously and that too without closing window, you can achieve that using following steps:
First of all remove the task1.Wait(). (do not block UI dispatcher)
Second, maintain bool to keep count that close event has been initiated.
Last, cancel closing event by setting e.Cancel = true and manually raise close event from task itself once you finished.
Relevant code:
bool closeInitiated = false;
private void poc_Closing(object sender, CancelEventArgs e)
{
if (!closeInitiated)
{
var task1 = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
myfunction();
}).ContinueWith((cc) => { });
closeInitiated = true;
e.Cancel = true;
}
}
private void myfunction()
{
App.Current.Dispatcher.Invoke(new Action(() =>
{
MessageBox.Show("test");
Close();
}));
}
I think the issue is at task1.Wait(); Go through this UI Thread Wait and DeadLock
I hope this will help.
I have gotten the same issue, and I figured the problem was that the Task where I'm invoking to, was already closed a second after clicking the Close button, so when the Invoking function takes a bit longer - it might crash.
If you still wanna execute this function, I used BeginInvoke instead of Invoke and it worked.
Here is my code:
if (app.Current.Dispatcher.CheckAccess()) //doesn't need to be invoked
myFunction();
else //coming from another thread need invoker
{
//at exiting program this task might already be canceled, so make sure it's not
if (!app.Current.Dispatcher.HasShutdownFinished)
app.Current.Dispatcher.Invoke(myFunction());
else
app.Current.Dispatcher.BeginInvoke(myFunction());
I am working on a legacy application that is built on top of NET 3.5. This is a constraint that I can't change.
I need to execute a second thread to run a long running task without locking the UI. When the thread is complete, somehow I need to execute a Callback.
Right now I tried this pseudo-code:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
_thread.Join();
// execute finalizer
The second option, which does not lock the UI, is the following:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
while(_thread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
// execute finalizer
Of course the second solution is not good cause it overcharge the UI.
What is the correct way to execute a callback when a _thread is complete? Also, how do I know if the thread was cancelled or aborted?
*Note: * I can't use the BackgroundWorker and I can't use the Async library, I need to work with the native thread class.
There are two slightly different kinds of requirement here:
Execute a callback once the long-running task has completed
Execute a callback once the thread in which the long-running task was running has completed.
If you're happy with the first of these, the simplest approach is to create a compound task of "the original long-running task, and the callback", basically. You can even do this just using the way that multicast delegates work:
ThreadStart starter = myLongRunningTask;
starter += () => {
// Do what you want in the callback
};
Thread thread = new Thread(starter) { IsBackground = true };
thread.Start();
That's very vanilla, and the callback won't be fired if the thread is aborted or throws an exception. You could wrap it up in a class with either multiple callbacks, or a callback which specifies the status (aborted, threw an exception etc) and handles that by wrapping the original delegate, calling it in a method with a try/catch block and executing the callback appropriately.
Unless you take any special action, the callback will be executed in the background thread, so you'll need to use Control.BeginInvoke (or whatever) to marshal back to the UI thread.
I absolutely understand your requirements, but you've missed one crucial thing: do you really need to wait for the end of that thread synchronously? Or maybe you just need to execute the "finalizer" after thread's end is detected?
In the latter case, simply wrap the call to myLongRunningTask into another method:
void surrogateThreadRoutine() {
// try{ ..
mytask();
// finally { ..
..all 'finalization'.. or i.e. raising some Event that you'll handle elsewhere
}
and use it as the thread's routine. That way, you'll know that the finalization will occur at the thread's and, just after the end of the actual job.
However, of course, if you're with some UI or other schedulers, the "finalization" will now run on yours thread, not on the "normal threads" of your UI or comms framework. You will need to ensure that all resources are external to your thread-task are properly guarded or synchronized, or else you'll probably clash with other application threads.
For instance, in WinForms, before you touch any UI things from the finalizer, you will need the Control.InvokeRequired (surely=true) and Control.BeginInvoke/Invoke to bounce the context back to the UI thread.
For instance, in WPF, before you touch any UI things from the finalizer, you will need the Dispatcher.BeginInvoke..
Or, if the clash could occur with any threads you control, simple proper lock() could be enough. etc.
You can use a combination of custom event and the use of BeginInvoke:
public event EventHandler MyLongRunningTaskEvent;
private void StartMyLongRunningTask() {
MyLongRunningTaskEvent += myLongRunningTaskIsDone;
Thread _thread = new Thread(myLongRunningTask) { IsBackground = true };
_thread.Start();
label.Text = "Running...";
}
private void myLongRunningTaskIsDone(object sender, EventArgs arg)
{
label.Text = "Done!";
}
private void myLongRunningTask()
{
try
{
// Do my long task...
}
finally
{
this.BeginInvoke(Foo, this, EventArgs.Empty);
}
}
I checked, it's work under .NET 3.5
You could use the Observer Pattern, take a look here:
http://www.dofactory.com/Patterns/PatternObserver.aspx
The observer pattern will allow you, to notify other objects which were previously defined as observer.
A very simple thread of execution with completion callback
This does not need to run in a mono behavior and is simply used for convenience
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class ThreadTest : MonoBehaviour
{
private List<int> numbers = null;
private void Start()
{
Debug.Log("1. Call thread task");
StartMyLongRunningTask();
Debug.Log("2. Do something else");
}
private void StartMyLongRunningTask()
{
numbers = new List<int>();
ThreadStart starter = myLongRunningTask;
starter += () =>
{
myLongRunningTaskDone();
};
Thread _thread = new Thread(starter) { IsBackground = true };
_thread.Start();
}
private void myLongRunningTaskDone()
{
Debug.Log("3. Task callback result");
foreach (int num in numbers)
Debug.Log(num);
}
private void myLongRunningTask()
{
for (int i = 0; i < 10; i++)
{
numbers.Add(i);
Thread.Sleep(1000);
}
}
}
Try to use ManualRestEvent to signal of thread complete.
Maybe using conditional variables and mutex, or some functions like wait(), signal(), maybe timed wait() to not block main thread infinitely.
In C# this will be:
void Notify()
{
lock (syncPrimitive)
{
Monitor.Pulse(syncPrimitive);
}
}
void RunLoop()
{
for (;;)
{
// do work here...
lock (syncPrimitive)
{
Monitor.Wait(syncPrimitive);
}
}
}
more on that here:
Condition Variables C#/.NET
It is the concept of Monitor object in C#, you also have version that enables to set timeout
public static bool Wait(
object obj,
TimeSpan timeout
)
more on that here:
https://msdn.microsoft.com/en-us/library/system.threading.monitor_methods(v=vs.110).aspx
I tried the following (pseudocode) but I always get a deadlock when Iam trying to stop my thread.
The problem is that Join() waits for the thread to complete and a pending Invoke() operation is also waiting to complete. How can I solve this?
Thread workerThread = new Thread(BackupThreadRunner);
volatile bool cancel;
// this is the thread worker routine
void BackupThreadRunner()
{
while (!cancel)
{
DoStuff();
ReportProgress();
}
}
// main thread
void ReportProgress()
{
if (InvokeRequired)
{
Invoke(ReportProgress);
}
UpdateStatusBarAndStuff();
}
// main thread
void DoCancel()
{
cancel=true;
workerThread.Join();
}
You could use BeginInvoke(ReportProgress) - that way your worker thread doesn't have to wait for the UpdateStatusBarAndStuff method to finish.
use `BeginInvoke' instead
I would do it a slightly different way:
private Thread workerThread;
void StartButtonClick()
{
workerThread = new Thread(ReportProgress);
thread.Start();
}
void CancelButtonClick()
{
// If you use a while(bool), it will repeat the task forever
// or with no while and just a bool, you'll have to check the value of the bool in each line
// so simply aborting it (providing you clean up) is accceptable.
workerThread.Abort();
// If you don't mind your user waiting:
// workerThread.Join(1000);
}
void ReportProgress()
{
if (InvokeRequired)
{
Invoke(ReportProgress);
return;
}
UpdateStatusBarAndStuff();
}
The best practice advice is "don't abort". This is based on the fact you don't know at what point the abort call will exit your code - it could be half way through creating a Stream. So you end up with a choice: can you guarantee that at whatever line the code exits, it will be in a reasonable state to do so?
If you can't then you will need to use a Thread.Join().
Even with a Thread.Join, the user may get bored and quit (ALT+F4) the app, and you have exactly the same situation as you had with the Thread.Abort() call.