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
Related
I try to log text messages from a Task or Thread to a textbox on my form. For that i use Invoke and InvokeRequired methods to syncronize with the main thread, as i can be found in many examples on the internet. See LogMessage_Delegate and LogMessage_Threadsafe below. When i close the app, a boolean flag finished is set to true and the task/thread should stop the work.
This all works fine until i set a breakpoint on the first line of the Form1_FormClosing event handler (finished = true;). Then i see only the console message "LogMessage InvokeRequired", but no corresponding "LogMessage" and the app is hanging.
If i comment out the LogMessage_Threadsafe call in Work (only console messages), then it works again. The app is closing, as expected.
So, can anybody explain this behavior to me? I can find no reason for it.
Please note, i do the flagging in the Form1_FormClosing event handler, so the form is still alive and working.
namespace MultiThreadedTest
{
public partial class Form1 : Form
{
//************************************************************
// Fields
Thread worker = null;
Task task = null;
bool finished = false;
//************************************************************
// Constructor
public Form1()
{
InitializeComponent();
worker = new Thread(Work);
worker.Start();
//task = Task.Factory.StartNew(Work);
}
//************************************************************
// Helper methods
public void LogMessage(string sMessage)
{
LogTextBox.Text += sMessage + Environment.NewLine;
}
/// <summary>
/// Threadsafe wrapper for LogMessage
/// </summary>
delegate void LogMessage_Delegate(string sMessage);
public void LogMessage_Threadsafe(string sMessage)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.InvokeRequired)
{
Console.WriteLine("LogMessage InvokeRequired");
LogMessage_Delegate callback = new LogMessage_Delegate(LogMessage_Threadsafe);
this.Invoke(callback, new object[] { sMessage });
}
else
{
Console.WriteLine("LogMessage");
LogMessage(sMessage);
}
}
//************************************************************
// Commands
void Work()
{
while (!finished)
{
Console.WriteLine("Tread/Task Waiting...");
LogMessage_Threadsafe("Tread/Task Waiting...");
Thread.Sleep(1000); // Wait a little...
}
Console.WriteLine("Thread/Task Done");
}
//************************************************************
// Events
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
finished = true;
if (worker != null) worker.Join();
if (task != null) Task.WaitAll(task);
Console.WriteLine("App Done");
}
}
}
You don't need to use raw threads since .NET 4 with the introduction of Tasks. Invoke wasn't needed either but became obsolete since .NET 4.5 with the introduction of async/await. 4.5 also introduced thread-safe progress reporting and cancellation with the IProgress< T> inteface and Progress< T> implementation, as explained in Async in 4.5: Enabling Progress and Cancellation in Async APIs.
Progress<T> calls its delegate on the thread it was created on, in this case the UI thread. You can pass the interface to any background method (task, thread method etc) and use it to report progress.
Given that the earliest supported .NET version is 4.5.2, you can assume these classes will always be available. BTW, TLS 1.2 support was added in 4.5.2 so any holdouts are forced to upgrade already, as they find they can't connect to GMail or other services that demand TLS 1.2.
Your code can be simplified a lot by using these classes. A quick&dirty form with a background timer and thread-safe reporting is the following:
public partial class Form1 : Form
{
System.Threading.Timer _timer;
IProgress<string> _progress;
public Form1()
{
InitializeComponent();
_progress = new Progress<string>(msg => textBox1.Text += msg + "\r\n");
_timer = new System.Threading.Timer(theCallback);
}
private async void theCallback(object state)
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(100);
_progress.Report($"Boo {i}");
}
}
private void Form1_Load(object sender, EventArgs e)
{
_timer.Change(0, 10000);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_timer.Dispose();
_timer = null;
_progress = null;
}
}
UPDATE
As for why the original code blocks, it's because Thread.Join() is called from the UI thread in Form.Closing. If the background thread tries to call Invoke to marshal a call to the UI thread, it will get blocked itself precisely because the UI thread is blocked.
This can be avoided by calling BeginInvoke instead of Invoke(). This was the typical way to handle callbacks into the UI thread before .NET 4.
The blocking behaviour can be seen in the Parallel Stacks debugger window (Debug / Windows / Parallel Stacks). When the form deadlocks, two stacks appear, one in the Form.Closing method and one in the LogMessage_Threadsafe method
If you're paused at a breakpoint in the UI thread, calls marshaled to the UI thread via Invoke won't execute, because they run on the UI thread, which is paused.
But judging from your comment, that doesn't seem to be the issue. So I would guess the problem is that, by pausing at that breakpoint, you've allowed the background thread to get into a state where it's blocking on Invoke(), and then you're trying to join that background thread, which will block until the Invoke completes, which will never happen.
As a separate issue, if you're accessing finished from multiple threads, you need to surround the reads and writes with lock blocks to ensure thread safety.
I have a worker thread that may be active for short bursts of time and idle for rest of the time. I'm thinking to put the thread to sleep and then awake it when needed.
Any additional recommendations for this I should be aware of?
Thanks!
this is in C#/.NET4
You should probably not be using a persistent worker thread- use the thread pool. This is exactly what it is intended for.
ThreadPool.QueueUserWorkItem(() => {
// My temporary work here
});
If you insist on having a persistent worker thread, make it run this:
// This is our latch- we can use this to "let the thread out of the gate"
AutoResetEvent threadLatch = new AutoResetEvent(false);
// The thread runs this
public void DoBackgroundWork() {
// Making sure that the thread is a background thread
// ensures that the endless loop below doesn't prevent
// the program from exiting
Thread.IsBackground = true;
while (true) {
// The worker thread will get here and then block
// until someone Set()s the latch:
threadLatch.WaitOne();
// Do your work here
}
}
// To signal the thread to start:
threadLatch.Set();
Also note that if this background thread is going to interact with the user interface at all, you'll need to Invoke or BeginInvoke accordingly. See http://weblogs.asp.net/justin_rogers/pages/126345.aspx
Just use an event to pause the worker thread: reset - paused, set - unpaused (working) state.
Here is the draft version of code that demonstrates the approach.
class Worker
{
private Thread _thread;
// Un-paused by default.
private ManualResetEvent _notToBePaused = new ManualResetEvent(true);
public Worker()
{
_thread = new Thread(Run)
{
IsBackground = true
};
}
/// <summary>
/// Thread function.
/// </summary>
private void Run()
{
while (true)
{
// Would block if paused!
_notToBePaused.WaitOne();
// Process some stuff here.
}
}
public void Start()
{
_thread.Start();
}
public void Pause()
{
_notToBePaused.Reset();
}
public void UnPause()
{
_notToBePaused.Set();
}
}
Signaling with WaitHandle is the right way to go, but just to add on what others said already
I'd usually go with 2 signals working together, otherwise you wouldn't know whether to 'continue' or 'exit' when needed - or would have to resort to a less graceful way of doing that (stopping the thread - of course there are other ways of doing something like this, just one 'pattern'). So usually it works with an 'exit' signal and a 'new work available' signal - working in unison. e.g.
WaitHandle[] eventArray = new WaitHandle[2] { _exitEvent, _newWorkEvent };
while ((waitid = WaitHandle.WaitAny(eventArray, timeout, false)) > 1)
{
// do your work, and optionally handle timeout etc.
}
note:
exit is ManualResetEvent with 'false' initial state - 'Set' event to exit.
_newWork is either Manual in which case you need to pause/continue from outside which is what you wanted I think -
...or could also be new AutoResetEvent(false) which you 'signal' to do one loop of work, signal returns to 'false' right away - and you need to repeat that for each 'new batch' of work - this is a bit simplified.
(often that goes hand in hand with some 'messages' being passed along, synchronized of course in some way).
Hope this adds some more info,
I've found little information on how to properly use the Dispatcher class on its own.
Currently I am using it similar to this question, but there is an inherent race condition which I do not see mentioned anywhere.
Assuming you use the following code to start a dispatcher thread:
Thread thread = new Thread(Dispatcher.Run);
thread.Start();
And try to use it later:
Dispatcher.FromThread(thread).Invoke(MyMethodDelegate);
This will often throw a NullReferenceException as the Dispatcher.FromThread call may return null since there is no guarantee that Dispatcher.Run has been called yet.
What I've done to implement this properly is to use a signal to ensure the dispatcher is running before continuing to use it on the main thread.
This is a shorter version, done as a utility function, inspired by yours so I left out the comments.
private static Thread CreateDispatcherThread()
{
using (var startedEvent = new ManualResetEventSlim())
{
var dispatcherThread = new Thread( _ => {
Dispatcher.CurrentDispatcher.BeginInvoke((Action)(startedEvent.Set));
Dispatcher.Run(); } );
dispatcherThread.Start();
startedEvent.WaitHandle.WaitOne();
return dispatcherThread;
}
}
Here is what I ended up doing, which is what I believe you need to do in order to use the Dispatcher properly.
private Thread executionThread;
private object SyncObject {get;set;}
private delegate void DispatcherMethod();
private void InitDispatcher()
{
this.SyncObject = new object();
// Set up the dispatcher pump. See Dispatcher.Run on MSDN.
this.executionThread = new Thread(StartDispatcher);
lock (this.SyncObject)
{
this.executionThread.Start();
Monitor.Wait(this.SyncObject);
}
}
private void StartDispatcher()
{
DispatcherMethod method = DispatcherStarted;
// Enqueue a started event by adding an initial method on the message pump.
// Use BeginInvoke because the dispatcher is not actually running yet.
// The call to Dispatcher.CurrentDispatcher handles creating the actual
// Dispatcher instance for the thread (see MSDN - Dispatcher.FromThread
// does not initialize the Dispatcher).
Dispatcher.CurrentDispatcher.BeginInvoke(method);
Dispatcher.Run();
}
private void DispatcherStarted()
{
lock (this.SyncObject)
{
Monitor.Pulse(this.SyncObject);
}
}
After InitDispatcher returns, you can use
Dispatcher.FromThread(executionThread).Invoke
or
Dispatcher.FromThread(executionThread).BeginInvoke
to marshal calls to the dispatcher thread.
I have a XAML application that serves as the UI for an automation. The entire automation can take anywhere from 20-30 hours to fully execute so I created a Task class object that essentially wraps Thread methods (Start/Stop/Reset).
However, when I run the automation method under the Task object, the XAML UI is busy and I cannot interact with the other controls, including the Pause button which toggles the Thread.Set() flag.
There is another post
Prevent UI from freezing without additional threads
where someone recommended the BackgroundWorker class this MSDN article mentions it is a bad idea to use this when if it manipulates objects in the UI, which mine does for purposes of displaying status counts:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Any idea around this?
private void OnButtonStartAutomationClick(object sender, RoutedEventArgs e)
{
btnPauseAutomation.IsEnabled = true;
Automation.Task AutomationThread = new Automation.Task(RunFullAutomation);
}
private void RunFullAutomation()
{
// do stuff that can take 20+ hours
// threaded so I can utilize a pause button (block)
}
class Task
{
private ManualResetEvent _shutdownFlag = new ManualResetEvent(false);
private ManualResetEvent _pauseFlag = new ManualResetEvent(true);
private Thread _thread;
private readonly Action _action;
public Task(Action action)
{
_action = action;
}
public void Start()
{
ThreadStart ts = new ThreadStart(DoDelegatedMethod);
_thread = new Thread(ts);
_thread.Start();
_thread.Priority = ThreadPriority.Lowest;
}
public void Resume()
{
_pauseFlag.Set();
}
public void Stop()
{
_shutdownFlag.Set();
_pauseFlag.Set();
_thread.Join();
}
private void DoDelegatedMethod()
{
do
{
_action();
}
while (!_shutdownFlag.WaitOne(0));
}
}
where someone recommended the BackgroundWorker class this MSDN article mentions it is a bad idea to use this when if it manipulates objects in the UI, which mine does for purposes of displaying status counts
BackgroundWorker is actually ideal for this, as it was designed for this type of scenario. The warning is that you shouldn't change UI elements inside of DoWork, but rather via ReportProgress and the ProgressChanged event.
The reason the warning exists is "DoWork" is executed on a background thread. If you set a UI element value from there, you'll get a cross threading exception. However, ReportProgress/ProgressChanged automatically marshals the call back into the proper SynchronizationContext for you.
Take a look at the Dispatcher object in WPF. You can, and should in your scenario, run the long running tasks on a background thread and the BackgroundWorker is a good way to do it. When you need to update the UI you need to verify access to the UI thread and if you don't have it use the dispatcher to invoke an update method on the UI thread.
There are two possible causes here: first, that the blocking task is blocking the UI thread rather than running on a background thread, and second, that the background thread is starving the UI thread so that it never gets the chance to respond to input. You need to find out which of these is the case. A crude way to do this is, in your Click handler, Debug.WriteLine the current thread ID (Thread.CurrentThread.ManagedThreadId), and do the same in the RunFullAutomation callback.
If these print the same number, then you have the first problem. Reed and TheZenker have provided solutions to this.
If these print different numbers, then you are already on a worker thread, and you have the second problem. (BackgroundWorker may get you to the worker thread more elegantly, and will help with updating the UI, but it won't stop starvation.) In this case the simplest fix is probably to set _thread.Priority = ThreadPriority.BelowNormal; before starting the worker thread.
By the way, your code never appears to actually call AutomationThread.Start, which means the RunFullAutomation callback isn't even executed. Is this just a typo?
I'd advise against rolling out your own Task class given that .NET 4 has full support for running tasks asynchronously in the background using the Task Parallel Library
That said,you can do what Reed suggests and use a BackgroundWorker which is ideal or if you prefer more control over the nature of how the task si executing, you could use the Task class from System.Threading.Tasks and implement something like so:
public partial class MainWindow : Window
{
CancellationTokenSource source = new CancellationTokenSource();
SynchronizationContext context = SynchronizationContext.Current;
Task task;
public MainWindow()
{
InitializeComponent();
}
private void DoWork()
{
for (int i = 0; i <= 100; i++)
{
Thread.Sleep(500); //simulate long running task
if (source.IsCancellationRequested)
{
context.Send((_) => labelPrg.Content = "Cancelled!!!", null);
break;
}
context.Send((_) => labelPrg.Content = prg.Value = prg.Value + 1, null);
}
}
private void Start_Click(object sender, RoutedEventArgs e)
{
task = Task.Factory.StartNew(DoWork, source.Token);
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
source.Cancel();
}
}
In DoWork() you use the WPF SynchronizationContext and post messages to update the UI wiget you need.
The example has a progress bar and a label control that is updated on each iteration of the for loop.Cancellation is supported using CancellationTokenSource which is checked in each iteration.
Hope this helps.
I am having a function where I have used a thread in c#.net.
I am having a another function on the next line of that thread. But this function has to be called only after the thread gets executed.
How can i do it ?
Example..
Somefunction()
{
// thread //(thread started)
add() (another function but need to be executed only tha above thread gets over)
}
Use a BackgroundWorker and include the function call in the worker completeted event handler.
var worker = new BackgroundWorker();
_worker.DoWork += delegate { DoStuff(); };
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
[...]
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
/// Do post-thread stuff
}
Use Thread.Join to block the current thread until the specified thread has finished execution.
Why start a separate thread if you want execution to be single threaded?
by "after the thread gets executed", do you mean it must have started? or it must have finished?
If you mean finished, then you would typically Join() the thread - but there is no point Join()ing a thread you have stared in the line before (just execute the code directly). The other approach is to use a "callback" at the end of the threaded method.
If you mean started, then you can do things like:
object lockObj = new object();
lock(lockObj) {
ThreadPool.QueueUserWorkItem(delegate {
lock(lockObj) {
Monitor.Pulse(lockObj);
}
// do things (we're on the second thread...)
});
Monitor.Wait(lockObj);
}
// thread has definitely started here
You can use , for instance, a ManualResetEvent.
When you start the processing on the other thread, you call the reset method.
When processing on the other thread has finished, you call set.
Then, the method that must be executed on the 'main thread', needs to wait until the ManualResetEvent has been set before it can execute.
For more info, you can have a look at the ManualResetEvent at MSDN.
If add() is thread safe, just call it at the end of the function you pass to create thread.
You could try the following, it may not work for your scenario: I can't tell given the amount of detail you provided:
First create a delegate:
public delegate int MyThreadSignature(Something arg);
Then use the Begin/End Invoke pattern:
var thread = new MyThreadSignature(WorkerMethod);
thread.BeginInvoke(theArg,
MyThreadEnded, /*Method to call when done*/,
thread /*AsyncState*/);
Create the MyThreadEnded method:
void MyThreadEnded(IAsyncResult result)
{
var thread = (MyThreadSignature)result.AsyncState;
var result = thread.EndInvoke(result);
// Call your next worker here.
}
The method to call MUST have the signature in the example: Name(IAsyncResult result).