Monday, January 30, 2012

Basic Threading in C#

Threading is a great way to make your application smoother. A single thread in a C# application, is an independent execution path that can run simultaneously with the main application thread. Of course, C# supports multithreading. And to use the threading namespace, you can directly call it from System.Threading, or import it:

1
using System.Threading;

Without this, a basic HTTP request makes your application unavailable in a span of time. And if you are using a progress bar, you won’t see it updating (since the application is unresponsive at this state).

Single Thread

The most basic way to implement this, is by using the Thread class. An example:

1
2
Thread tMain = new Thread(new ThreadStart(someMethod));
tMain.Start();

Wherein someMethod is a void function that contains the code you want to execute. With this, the thread will execute in parallel with the main thread. The only drawback, is you cannot modify controls created in the main thread like you normally use to. This will result into a Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on exception. The solution is pretty simple:

1
2
3
4
5
// Won't Work
textBox1.Text = "Hello";
// Will Work
this.Invoke(new MethodInvoker(delegate { textBox1.Text = "Hello"; }));

This approach functions just the same as a BackgroundWorker instance.

Powertip: You can disable all the controls in your form painlessly without setting the Enabledproperty of each control (imagine having 20+ controls in your form).

1
2
3
4
5
6
7
private void controlsEnableToggle(bool val)
{
foreach (Control c in this.Controls)
{
c.Enabled = val;
}
}

Multiple Threads

Dealing with multiple repetitive tasks with a single line of execution is painful, especially in large numbers. C# supports multithreading. This means, we can initiate as many threads as we like, and it will do the job. So how to do that? A simple for-loop.

1
2
3
4
for (int i = 0; i < 10; i++) {
Thread tMain = new Thread(new ThreadStart(someMethod));
tMain.Start();
}

The above code works, but what if we need to supply parameters to our method?

01
02
03
04
05
06
07
08
09
10
11
// .NET 2
for (int i = 0; i < 10; i++) {
Thread tMain = new Thread(new ParameterizedThreadStart(someMethod));
tMain.Start(param);
}
// .NET 3.5 & 4
for (int i = 0; i < 10; i++) {
Thread tMain = new Thread(unused => someMethod(param));
tMain.Start();
}

Pausing and Stopping Threads

Whenever you close a form, the main thread will stop, but the threads you created are not. Thus, the process is still alive. To stop this, you can just go to the task manager, and end the process from there. But that’s not user-friendly.

You cannot actually stop or pause threads immediately. You can never tell what the thread is doing, and terminating them abnormally may cause side effects. For this, ManualResetEvent is used.

1
2
ManualResetEvent pauseEvent = new ManualResetEvent(true);
ManualResetEvent stopEvent = new ManualResetEvent(false);

The bool values passed to the constructor indicates whether the initial state of the instance is signaled or not. This is pretty easy to use.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
ManualResetEvent pauseEvent = new ManualResetEvent(true);
ManualResetEvent stopEvent = new ManualResetEvent(false);
private void someMethod(string param) {
// Stops the thread
if (stopEvent.WaitOne(0))
return;
// Pauses the thread
pause Event.WaitOne(Timeout.Infinite);
// Your code
}

To change the signaled state of these events, we will use Reset and Set methods. Here’s how to use them in relation to the above code:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
// Stops the threads
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
stopEvent.Set();
}
// Pauses the threads
private void Button1_Click(object sender, EventArgs e)
{
pauseEvent.Reset();
}
// Resumes the threads
private void Button2_Click(object sender, EventArgs e)
{
pauseEvent.Set();
}

You can choose how you will use the methods, the above is just an example.

No comments:

Post a Comment