Notifying about task finishing its work - c#

I'm thinking of a simple way of reacting on task finishing its work. I came up with the following solution (paste it to WinForms application with a single button to test):
public partial class Form1 : Form
{
private Thread thread;
public void DoFinishWork() {
// [4]
// UI thread - waiting for thread to finalize its work
thread.Join();
// Checking, if it really finished its work
MessageBox.Show("Thread state: " + thread.IsAlive.ToString());
}
public void DoWork() {
// [2]
// Working hard
Thread.Sleep(1000);
}
public void FinishWork() {
// [3]
// Asynchronously notifying form in main thread, that work was done
Delegate del = new Action(DoFinishWork);
this.BeginInvoke(del);
// Finalizing work - this should be switched
// at some point to main thread
Thread.Sleep(1000);
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
// [1]
// Schedule the task
ThreadStart start = new ThreadStart(DoWork);
// Schedule notification about finishing work
start += FinishWork;
thread = new Thread(start);
thread.Start();
}
}
This is meant to be a simple cancel scenario, so there will be only one thread, which will be running in parallel to the UI thread.
Is there a simpler (or more thread-safe) way of implementing this kind of notification for the Thread?
Please take into consideration two facts:
The only way i can terminate the thread is to Abort it (that's because I have no control over what is being done in the thread - 3rd party code)
Thus, I cannot use BackgroundWorker, because it only provides way of graceful termination.

Is there a simpler (or more thread-safe) way of implementing this kind of notification for the Thread?
Yes, use the TPL and let the framework worry about managing the thread
Task.StartNew(() => {
// do some stuff
}).ContinueWith((task) => {
// do some stuff after I have finished doing some other stuff
});
Or alternatively, since you are working with WinForms, use a BackgroundWorker and handle the RunWorkerCompleted event.
I mistook your notion of kill for cancel - there is no reliable way of actually killing a thread in .NET, even the documentation suggests that using Abort is more or less a gamble and gives absolutely no guarentees that the thread will actually be killed. Also, it will leave the thread and, as a consequence, the application in an unpredictable state so if you are willing to take that risk then that's up to you.
One alternative is to simply let the thread play out but just ignore the results, depending on the size of the task it might not be that big a deal.

Although you need Abort to kill the thread, you can still use the TPL. You could start that thread within the task, and wait for it as well as for an CancellationToken. When the task is cancelled before the thread finishes, you can call Abort on the thread.
It would look something like that:
// In your class:
ManualResetEvent threadFinished = new ManualResetEvent(false);
// In your calling function (button1_Click):
Task.Run( () => {
ThreadStart threadStart = new StreadStart(DoWork);
threadStart += () => { threadFinished.Set(); }
Thread thread = new Thread(threadStart);
threadFinished.Reset();
thread.Start();
WaitHandle waitCancel = cancellationToken.WaitHandle;
int waited = WaitHandle.WaitAny( new WaitHandle[]{ waitCancel, threadFinished } );
if (waited == 0 && cancellationToken.IsCancellationRequested)
thread.Abort();
else
thread.Join()
});

Related

Why Thread.Join() DOES hang my application when called on UI thread?

According to answer for this question Why Thread.Join() DOES NOT hang my application when called on UI thread? thread.Join should not hang UI if it called from STA thread. I used the same code as in linked question
private void button1_Click(object sender, EventArgs e)
{
string retValue = "";
Thread thread = new Thread(
() =>
{
retValue = LongRunningHeavyFunction();
});
thread.Start();
thread.Join();
button1.Text = retValue;
}
private string LongRunningHeavyFunction()
{
Thread.Sleep(5000);
return "Done";
}
Method Main in class Program marked as [STAThread]. But when I press button UI is freezed, I can't drag window etc. I'm confused. Am I missed something? Why UI is freezed in my case?
Thread.Sleep causes UI to freeze.
If you want to wait for a while in LongRunningHeavyFunction(), use a timer object.
Here is an example, how to use timer:
How to use a timer to wait?
thread.Join() tells the current thread to await thread. In this case, the current thread is the GUI thread, and you're telling it to await the worker thread. As a result, your GUI thread does nothing until the worker thread completes. And since the GUI thread is doing nothing, it isn't handling normal GUI activities, causing the freeze.
The solution is to not block your GUI. Instead, run your long-running process without awaiting it, such that your GUI thread can keep responding to the user. Then, once the long-running process does complete, use the GUI dispatcher to call back to set the result.
The code might look something like this:
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(
() =>
{
// Perform work
var retValue = LongRunningHeavyFunction();
// Call the GUI thread
button1.Dispatcher.BeginInvoke(() =>
{
// .Dispatcher called the GUI thread.
// This code happens back in the GUI thread once the
// worker thread has completed.
button1.Text = retValue;
});
});
thread.Start();
}
private string LongRunningHeavyFunction()
{
Thread.Sleep(5000);
return "Done";
}

c# thread and a waiting form

I connect to a webserive. While the webservice is connected i want to have a waiting form with an animated gif inside of it. The waiting form is correctly displayed but the animated give is not animated it is fixed.
Can anybody help me. I have already tried : DoEvents but the gif is still not animated.
// Create the new thread object
Thread NewThread = new Thread(new ThreadStart(RunThread));
// Start the new thread.
NewThread.Start();
// Inform everybody that the main thread is waiting
FRM_Wait waitingDialog = new FRM_Wait();
waitingDialog.Show();
waitingDialog.Activate();
Application.DoEvents();
// Wait for NewThread to terminate.
NewThread.Join();
// And it's done.
waitingDialog.Close();
MessageBox.Show("Upload erfolgreich erledigt.", "Upload Erfolgreich",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
public void RunThread()
{
mfsportservicedev.ServiceSoapClient servicedev = new mfsportservicedev.ServiceSoapClient();
int status = servicedev.addEvent(videosNames, videos);
}
Don't call Join on a thread from within the UI thread. Instead, disable any controls you don't want to act on until the task has completed (e.g. buttons) and then call back into the UI thread when the operation has completed - so move the "And it's done" code into a new method which is invoked at the end of the operation. If you're using .NET 4, I'd suggest using the TPL for this, as it makes it easier to represent "a task which is in progress" and to add a continuation to it. (It's also a good start for what will become the idiomatic way of doing async operations in .NET 4.5.)
The problem is coming from your join. join is synchronous, so basically you are making your UI wait till the thread finishes its work.
You want to use a callback function to come back to your UI.
Edit : ive been skeetified
You problem is here:
NewThread.Join();
This blocks the UI thread until NewThread ends.
Here's one way to do it:
private myDelegate;
// ...
myDelegate = new Action(RunThread);
myDelegate.BeginInvoke(new AsyncCallback(MyCallback),null);
// You RunThread method is now running on a separate thread
// Open your wait form here
// ...
// This callback function will be called when you delegate ends
private void MyCallback(IAsyncResult ar)
{
myDelegate.EndInvoke(ar);
// Note this is still not the UI thread, so if you want to do something with the UI you'll need to do it on the UI thread.
// using either Control.Invoke (for WinForms) or Dispatcher.Invoke (for WPF)
}
Thread.Join is a blocking call that does not pump messages so that is your problem. It is typically advised to avoid calling any kind of synchronization mechanism that causes the UI thread to block.
Here is a solution using the Task class and the Invoke marshaling technique.
private void async InitiateWebService_Click(object sender, EventArgs args)
{
FRM_Wait waitingDialog = new FRM_Wait();
waitingDialog.Show();
Task.Factory.StartNew(
() =>
{
mfsportservicedev.ServiceSoapClient servicedev = new mfsportservicedev.ServiceSoapClient();
int status = servicedev.addEvent(videosNames, videos);
waitingDialog.Invoke(
(Action)(() =>
{
waitingDialog.Close();
}));
});
}
Here is a solution using a raw Thread.
private void async InitiateWebService_Click(object sender, EventArgs args)
{
FRM_Wait waitingDialog = new FRM_Wait();
waitingDialog.Show();
var thread = new Thread(
() =>
{
mfsportservicedev.ServiceSoapClient servicedev = new mfsportservicedev.ServiceSoapClient();
int status = servicedev.addEvent(videosNames, videos);
waitingDialog.Invoke(
(Action)(() =>
{
waitingDialog.Close();
}));
});
thread.Start();
}
C# 5.0 makes this kind of pattern even easier with its new async and await keywords1.
private void async InitiateWebService_Click(object sender, EventArgs args)
{
FRM_Wait waitingDialog = new FRM_Wait();
waitingDialog.Show();
await Task.Run(
() =>
{
mfsportservicedev.ServiceSoapClient servicedev = new mfsportservicedev.ServiceSoapClient();
int status = servicedev.addEvent(videosNames, videos);
});
waitingDialog.Close();
}
1Not yet released.

Wait thread question

I have a UserControl with a tree on it. It uses multithreading to add nodes to it. I have a function called Expand which I need to execute after filtering completed and since I'm a newbie with multithreading I'm not sure how to do that. Here's my code:
class MyClass : UserControl
{
private Thread nThread;
private bool searchLoadCompleted = false;
private void Filter()
{
ClearTree();
this.nThread = new Thread(new ParameterizedThreadStart(AddFilteredResultsToTree));
this.nThread.IsBackground = true;
this.nThread.Start(someParameter);
}
private void AddFilteredResultsToTree(int someParameter)
{
myTree.Invoke(new MethodInvoker( ()=> this.searchLoadCompleted = false ));
myTree.Invoke(new MethodInvoker( ()=> AppendNode(......) ));
myTree.Invoke(new MethodInvoker( ()=> this.searchLoadCompleted = true ));
}
private void Expand()
{
}
}
I tried to add nThread.Join() into Expand() but it got stuck indefinitely. What should I do?
If the singlethreaded version of this is:
ClearTree();
AddFilteredResultsToTree(someparameter);
Expand();
Don't bother going multithreading, just do it on the same thread. The point of using multithreading there would be to let the main thread handle UI events, if you join the thread then you're basically just launching a background thread while freezing (not doing any work) in the main thread. Note that by calling Invoke you're actually delegating the execution of AddFilteredResultsToTree to the main thread anyway.
I'd suggest you simply call Expand from AddFilteredResult and use the Dispatcher to update the UI if needed or.
Another way to go (best in my opinion) would be to use the Async Pattern for this (example and tutorial here), and then on the AsyncCallback update the UI.
Calling Invoke will block both the GUI thread and your worker thread so there won't be any performance improvement over code without a worker thread.

How to Cancel a Thread?

In case of BackgroundWorker, a cancel can be reported by the e.Cancel - property of the DoWork - event handler.
How can I achieve the same thing with a Thread object?
Here is a full example of one way of doing it.
private static bool _runThread;
private static object _runThreadLock = new object();
private static void Main(string[] args)
{
_runThread = true;
Thread t = new Thread(() =>
{
Console.WriteLine("Starting thread...");
bool _localRunThread = true;
while (_localRunThread)
{
Console.WriteLine("Working...");
Thread.Sleep(1000);
lock (_runThreadLock)
{
_localRunThread = _runThread;
}
}
Console.WriteLine("Exiting thread...");
});
t.Start();
// wait for any key press, and then exit the app
Console.ReadKey();
// tell the thread to stop
lock (_runThreadLock)
{
_runThread = false;
}
// wait for the thread to finish
t.Join();
Console.WriteLine("All done.");
}
In short; the thread checks a bool flag, and keeps runing as long as the flag is true. I prefer this approach over calling Thread.Abort becuase it seems a bit nicer and cleaner.
Generally you do it by the thread's execute being a delegate to a method on an object, with that object exposing a Cancel property, and the long-running operation periodically chercking that property for tru to determine whether to exit.
for example
public class MyLongTunningTask
{
public MyLongRunninTask() {}
public volatile bool Cancel {get; set; }
public void ExecuteLongRunningTask()
{
while(!this.Cancel)
{
// Do something long running.
// you may still like to check Cancel periodically and exit gracefully if its true
}
}
}
Then elsewhere:
var longRunning = new MyLongTunningTask();
Thread myThread = new Thread(new ThreadStart(longRunning.ExecuteLongRunningTask));
myThread.Start();
// somewhere else
longRunning.Cancel = true;
A blocked thread can be stopped prematurely in one of two ways:
Thread.Interrupt
Thread.Abort
The main question is if the thread works on any ressources which need to be released correctly - in this case - you need to work with a property on the actual object which runs the thread.
There's Thread.Abort, which works by injecting a ThreadAbortException into the thread. It's a little risky because:
Your thread can get stuck if it's executing native code at the time
The code in the thread better be exception-safe, because this ThreadAbortException could happen on any line of code within it, even something innocent like i = i + 1
You're better off coding your own signalling mechanism between your GUI thread and the background thread. It's hard to recommend something without knowing what's going on inside that thread, but where I have a thread that works by waiting on some object in a loop, I use an AutoResetEvent and wait on that too.

What are alternative ways to suspend and resume a thread?

The two methods Thread.Suspend() and Thread.Resume() are obsolete since .NET 2.0. Why? What are other alternatives and any examples?
You'll want to use an AutoResetEvent EventWaitHandle.
Say you want to do something like this (NOTE: don't do this!):
private Thread myThread;
private void WorkerThread()
{
myThread = Thread.CurrentThread;
while (true)
{
myThread.Suspend();
//Do work.
}
}
public void StartWorking()
{
myThread.Resume();
}
Like others have said, this is a bad idea. Even though only using Suspend on its own thread is relatively safe, you can never figure out if you're calling Resume when the thread is actually suspended. So Suspend and Resume have been obsoleted.
Instead, you want to use an AutoResetEvent:
private EventWaitHandle wh = new AutoResetEvent();
private void WorkerThread()
{
while(true)
{
wh.WaitOne();
//Do work.
}
}
public void StartWorking()
{
wh.Set();
}
The worker thread will wait on the wait handle until another thread calls StartWorking. It works much the same as Suspend/Resume, as the AutoResetEvent only allows one thread to be "resumed".
The good alternatives all work by the thread reaching a point where it is happy to wait. Suspend was dangerous because it could suspend the thread while it was holding a lock on a mutex - a recipe for deadlocks.
So what your thread needs is a ManualResetEvent that it can Wait on - at a time when it is safe for it to do so, when it is not holding any locks.
This is the best tutorial ever for Thread (for C#): http://www.albahari.com/threading/
For wait you need to use .Join() on the thread. This will wait until tread finish is job. Other wise you will need to use Wait/Pulse.
you can use ManualReset instead of AutoReset:
public class Worker
{
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Start()
{
_thread = new Thread(DoWork);
_thread.Start();
Console.WriteLine("Thread started running");
}
public void Pause()
{
_pauseEvent.Reset();
Console.WriteLine("Thread paused");
}
public void Resume()
{
_pauseEvent.Set();
Console.WriteLine("Thread resuming ");
}
public void Stop()
{
// Signal the shutdown event
_shutdownEvent.Set();
Console.WriteLine("Thread Stopped ");
// Make sure to resume any paused threads
_pauseEvent.Set();
// Wait for the thread to exit
_thread.Join();
}
public void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_shutdownEvent.WaitOne(0))
break;
// Do the work..
Console.WriteLine("Thread is running");
}
}
}
That one is too long. What I need is a quick example codes to use. I found one from the discussion and answered by Mark R. Dawson at http://bytes.com/groups/net-c/458947-thread-suspend. It explains the danger of the obsolete methods and how to use AutoResetEvent to notify the second thread to continue processing.
I agree that is a great tutorial. The main reason Suspend() and Resume() are obsolete is because they are pretty dangerous methods. At any point Thread t could be doing anything. Anything. Imagine your thread is reading a file and has a lock on it. You suspend your thread. File stays locked. Same goes for any other resources. Same goes for a lock on a mutex.
The reasons why Thread.Suspend() and Thread.Resume() are obsolete or removed in .NET are largely the same reasons why Thread.suspend() and Thread.resume() are obsolete in Java. Compare—
Java's thread primitive deprecation FAQ (suspend "is inherently deadlock prone"), with
Mark R. Dawson's answer on .NET's Thread.Suspend()` ("if you stop a thread in mid execution you can run into deadlock and race conditions").
Solution:
Have a thread only resume another thread if the other thread has suspended itself.
Thus, the first thread only resumes the other thread if the other thread suspended itself (ie. its ThreadState = Suspended), and, thus, made itself ready to be resumed. This seems safe & flawless.
Or, am I not understanding .Net threading?

Categories

Resources