Abstract
In this article I explain how a resource intensive job is sourced out to its own thread. Furthermore I will discuss how to stay in communication with that thread. The article is for a Windows Forms application using C# in the .NET framework.
I will not talk about the theoretical concept of threading or event handling. It is assumed that you either know this or know where to learn about. (Or don’t know and even don’t want to know but simply make your application run.)
A source file is provided that contains a class with some templates for easy interthread communication.
The solution is to run the computation in its own thread. This is really easy:
In this example, the method
at the Begin of the code. If the user wants to abort the computation, the following would be a rough but effective way to do so:
I think there are better ways to achieve this since any intermediate results will probably be lost. However, for the case I had to solve this was an appropriate choice.
replacing
For my Windows Forms application I have created a form with a text box that will accept the kernel output. Therefore the class has a method
that takes a string and adds it to the text box. But this method can’t be called from the kernel. Event handlers are the solution of choice. As announced, I won’t explain the concept of event handling but simply give the solution.
Let’s go to the class that wants to write something to the text box. We want to have something like a
Now we can declare our delegate
and an event
Now we could fire this event using
But not only that this are three lines of code for what we wanted to have a simple function it, even worse, also makes our application crash! The first problem can be solved by defining a method that does the job of declaring the event arguments an firing the event. The second problem is because the event is fired but nobody cares about. We should check this before we fire it. Here is the handy method:
Now we’ve subscribed a method to the event that will be called as it is fired. Whops, that doesn’t work! This is because as the method is subscribed to the event in the kernel class, it is also called from the thread the kernel runs on. This is not the thread the text box is managed on. Fortunately, the .NET framework provides us a good workaround. We rewrite the
That’s it!
The definition of the
I will not talk about the theoretical concept of threading or event handling. It is assumed that you either know this or know where to learn about. (Or don’t know and even don’t want to know but simply make your application run.)
A source file is provided that contains a class with some templates for easy interthread communication.
Multithreading
In many applications one would like to carry out a computation in the background. I.e. the user interface shouldn’t “freeze” while the computation is running. Assume for example, a user started the evaluation by accident. He won’t be very pleased having to wait several minutes (or even longer) until he can correct his mistake.The solution is to run the computation in its own thread. This is really easy:
private void button_Click(object sender, EventArgs e)
{
private Thread kernel_thread;
kernel_thread = new Thread(compute);
kernel_thread.Start();
}
private void compute()
{
// Here a complex job is carried out.
}
In this example, the method
compute()
will run in its own thread named kernel_thread
. Note that compute()
must be void and mustn’t take any arguments. Don’t forget to addusing System.Threading;
at the Begin of the code. If the user wants to abort the computation, the following would be a rough but effective way to do so:
private void kill_kernel()
{
if (kernel_thread != null)
{
kernel_thread.Abort();
}
}
I think there are better ways to achieve this since any intermediate results will probably be lost. However, for the case I had to solve this was an appropriate choice.
Event Handling
Everything is cute and dandy but yet the user doesn’t know what the “kernel” is doing. In fact, we would like to be able to communicate with it. Communication is a vast field but the very least we would like to do is enabling the kernel to print some status information. Writing a console application one could simply useprint("I'll be finished soon!");
replacing
print
by whatever command is appropriate for the chosen language.For my Windows Forms application I have created a form with a text box that will accept the kernel output. Therefore the class has a method
public void log_print(string text)
{
text_box.AppendText(text);
text_box.AppendText(Environment.NewLine);
}
that takes a string and adds it to the text box. But this method can’t be called from the kernel. Event handlers are the solution of choice. As announced, I won’t explain the concept of event handling but simply give the solution.
Let’s go to the class that wants to write something to the text box. We want to have something like a
notify()
method. Do get it, we first have to declare a delegate that will be invoked at the event. This handler must be void and take an object and an instance of the EventArgs
class as argument. However, if we want to have it more customized, we can declare our own class that is derived from the EventArgs
class. In our case, we want to send a string so we definepublic class EventArgsNotification : EventArgs
{
public string info_text; // The text we want to send.
}
Now we can declare our delegate
public delegate void EventHandlerNotification(object sender, EventArgsNotification e);
and an event
public static event EventHandlerNotification EventNotification;
Now we could fire this event using
EventArgsNotification e = new EventArgsNotification();
e.info_text = message;
EventNotification(this, e);
But not only that this are three lines of code for what we wanted to have a simple function it, even worse, also makes our application crash! The first problem can be solved by defining a method that does the job of declaring the event arguments an firing the event. The second problem is because the event is fired but nobody cares about. We should check this before we fire it. Here is the handy method:
private void notify(string message)
{
if (EventNotification != null)
{
EventArgsNotification e = new EventArgsNotification();
e.info_text = message;
EventNotification(this, e);
}
}
Subscribing to the Event
Now we have defined an event and can use it. But if it is fired, no one cares. In fact, it isn’t even fired because we check it for not being null. An event is something like a list of functions subscribing to it. So next we have to go to our class that contains the text box and add the following:// Method that should be called if an event is fired:
private void receive_notification(object sender, EventArgsNotification e)
{
log_print(e.info_text);
}
// Subscribe:
kernel.EventNotification += receive_notification;
Now we’ve subscribed a method to the event that will be called as it is fired. Whops, that doesn’t work! This is because as the method is subscribed to the event in the kernel class, it is also called from the thread the kernel runs on. This is not the thread the text box is managed on. Fortunately, the .NET framework provides us a good workaround. We rewrite the
receive_notification
method as follows:private void receive_notification(object sender, EventArgsNotification e)
{
if (InvokeRequired)
{
Invoke(new EventHandlerNotification(receive_notification), new object[] { sender, e });
}
else
{
log_print(e.info_text);
}
}
InvokeRequired
is true if the event is fired from a different thread. In this case, the above method will simply fire the event again from it’s own thread. (That’s what Invoke
does.) This tools are provided in the ComponentModel
so we add at the beginningusing System.ComponentModel;
That’s it!
Making Everything more Comfortable
Maybe we have a lot of classes that want to be able to notify the user. Doing all the stuff in each of them is a tedious exercise. I have written a little static class that allows to use fire a notification event from any class (on any thread) usingcommunication.FireNotification(this, );
The definition of the
EventArgsNotification
class is also included in this file. It is static so an instantiation is not necessary. To subscribe to the event the same code as above is sufficient. Please don’t forget to correct the namespace to the one of your project.using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace example // PUT YOUR NAMESPACE HERE! { public delegate void EventHandlerNotification(object sender, EventArgsNotification e); public static class communication { public static event EventHandlerNotification EventNotification; ////// Fires a 'Notification' Event. The method is static an therefore can be accessed from any class without instantiation. /// /// Object that fires the event. /// Notification message (free text). public static void FireNotification(object sender, string message) { if (EventNotification != null) { EventArgsNotification e = new EventArgsNotification(); e.info_text = message; EventNotification(sender, e); } } } ////// A class used to send and receive textual information. /// public class EventArgsNotification : EventArgs { public string info_text; } }
Blog content from http://mklammler.wordpress.com