![]() |
General Programming »
Threads, Processes & IPC »
Threading
Intermediate
A C# class to invoke almost any method from a worker threadBy Xiangyang Liu 刘向阳C# code that makes multithreading easier |
C#.NET 1.0, .NET 1.1, Win2K, WinXP, Win2003, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
To readers: This article was posted last week under a different title. I deleted it later because the code does not really make multithreading easier, it requires you to derive a class from my base class and then override a virtual method. The current version is much simpler. I hope you find it useful, too.
When programming with C/C++, you can create a new thread using the Win32 API CreateThread. This API allows you to pass the address of a function and a pointer as its parameter. The function will be executed in a new thread. But you cannot use just any function as the thread function and you have to cast the input pointer to a structure or a class to access various values you need in the thread function. Or you can access global variables within the thread function to get input values.
With .NET, threading is supposed to be easier. However, the thread function you use in .NET cannot take any input parameter directly. You need to do some work to pass parameters to your worker thread, you can find out how to do it from MSDN.
In this article, I will introduce a C# class, ThreadHelper, that allows you to call almost any method that takes any number of parameters from a new worker thread. For example, you can use it to call a method in a .NET framework class or a third-party DLL from a new thread. The helper class also provides a way for you to get the output value of your function from the new thread.
The purpose of this class is to hide some boring details of using the .NET thread classes and make it easier for you to create a new worker thread in your application. If you are the kind of developer who always wants to know everything in your application, then this class is probably of little interest to you.
Here are the public methods of the ThreadHelper class.
// the constructor
public ThreadHelper();
// set a parameter value for the method you want to invoke
public void SetParameter(Object oValue);
// set the delegate (pointer) of the method you want to invoke
publicvoid SetMethod(Delegate pMethod);
// start a new thread and execute the method you specified
public bool StartThread();
// wait for the worker thread to finish
// warning: this method will block until the new thread is terminated
public void WaitForThread();
// get the error string
public String GetErrorMessage();
// get the output value
public Object GetOutput();
// reset all data so that the object can be reused
public void Reset();
Suppose you have a class MyDataClass as follows. The static member function GetData connects to a specified database and executes a query to retrieve data into a DataSet object.
class MyDataClass
{
public static DataSet GetData(String sConnection, String sSQL)
{
// the implementation
};
};
You may want to call this static member function to get data from several different databases simultaneously. Using the ThreadHelper class, here is what you need to do:
GetData method.
ThreadHelper objects.
SetParameter, SetMethod, and StartThread.
WaitForThread, GetErrorMessage and GetOutput. Here is the code for the above example:
// define a delegate (pointer) for your method
public delegate String myDelegate(String sConnection, String sSQL);
...
// create three helper objects
ThreadHelper objHelper1 = new ThreadHelper();
ThreadHelper objHelper2 = new ThreadHelper();
ThreadHelper objHelper2 = new ThreadHelper();
// set the delegate (pointer) of your method
objHelper1.SetMethod(new myDelegate(MyDataClass.GetData));
objHelper2.SetMethod(new myDelegate(MyDataClass.GetData));
objHelper3.SetMethod(new myDelegate(MyDataClass.GetData));
// set the connection string parameter
objHelper1.SetParameter(sConnection1);
objHelper2.SetParameter(sConnection2);
objHelper3.SetParameter(sConnection3);
// set the sql statement parameter
objHelper1.SetParameter(sStatement1);
objHelper2.SetParameter(sStatement2);
objHelper3.SetParameter(sStatement3);
// start the worker thread
objHelper1.StartThread();
objHelper2.StartThread();
objHelper3.StartThread();
// wait for the worker thread to finish
objHelper1.WaitForThread();
objHelper2.WaitForThread();
objHelper3.WaitForThread();
// process the output of the method called in the new thread
Object oOutput = ObjHelper1.GetOutput();
...
As you can see, it is easy to call a method from a new worker thread with the help of ThreadHelper and you don't have to know anything about the thread classes in .NET.
Note: If your method has multiple parameters, you need to call SetParameter multiple times and the calls have to be in the same order as the parameters appear in the method signature. The same ThreadHelper object cannot be used simultaneously in different threads. You need to use a separate helper object for each concurrently running thread. If you call the Reset method after the worker thread finishes, then the helper object can be reused to start another thread.
I have included a C# console application ThreadHelperTest.exe with this article. The application uses ThreadHelper to start two worker threads, each calls the non-static Test method of class MyTest. Here is the corresponding code:
...
public delegate bool TestCall(String sName, int nTest);
...
MyTest objTest = new MyTest();
ThreadHelper objHelper1 = new ThreadHelper();
ThreadHelper objHelper2 = new ThreadHelper();
objHelper1.SetMethod(new TestCall(objTest.Test));
objHelper2.SetMethod(new TestCall(objTest.Test));
objHelper1.SetParameter("Bill");
objHelper2.SetParameter("George");
objHelper1.SetParameter(1);
objHelper2.SetParameter(2);
objHelper1.StartThread();
objHelper2.StartThread();
objHelper1.WaitForThread();
objHelper2.WaitForThread();
String sError1 = objHelper1.GetErrorMessage();
String sError2 = objHelper2.GetErrorMessage();
if(sError1=="")
{
System.Console.WriteLine("Output of test 1: " +
objHelper1.GetOutput().ToString());
}
else System.Console.WriteLine("Error in test 1: " + sError1);
if(sError2=="")
{
System.Console.WriteLine("Output of test 2: " +
objHelper2.GetOutput().ToString());
}
else System.Console.WriteLine("Error in test 2: " + sError2);
The following is the console output from this test application:
Hello, Bill
This is test 1
The thread id is 2
Hello, George
This is test 2
The thread id is 3
Hello, Bill
This is test 1
The thread id is 2
Hello, George
This is test 2
The thread id is 3
Hello, Bill
This is test 1
The thread id is 2
Hello, George
This is test 2
The thread id is 3
Output of test 1: True
Output of test 2: True
Note: The ThreadHelper class is supposed to make your multithreading code easier. It uses DynamicInvoke internally, which may be a little slower than the standard way (late binding vs. early binding). Also, you need to make sure that the method you want to execute in a new thread is thread-safe if it will be used concurrently in multiple threads.
Thank you for reading my articles.
| You must Sign In to use this message board. | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 2 Nov 2003 Editor: Smitha Vijayan |
Copyright 2003 by Xiangyang Liu 刘向阳 Everything else Copyright © CodeProject, 1999-2009 Web18 | Advertise on the Code Project |