Introduction
The threads class is used to create and manipulate managed threads. In the .NET environment, it is the same class used for all .NET enabled languages. The .NET threads catch all the threads executed in the managed threads. We can't access the unmanaged threads from the managed threads. Thread.GetHashCode
is used to find the managed threads. Managed threads are executed in the .NET Common Language Runtime environment. Microsoft doesn't recommend mixing managed and unmanaged threads.
Managed Threads
Managed threads start when the System.Threading.Thread.Start
method is called. This method is used to start the managed threads. When a user creates the threads, we can use ThreadStart
delegate or a ParameterizedThreadStart
delegate for creating the threads. The ThreadStart
delegate is used to start the thread without any parameters. We can pass the argument using the Start
method.
The ParameterizedThreadStart
delegate is used to create a thread to pass an Object
as an argument. If we call the Start
method more than once, it throws a ThreadStateException
exception. The following example shows how to create the managed threads:
ref class ThreadClass
{
public:
static void ThraedClassMethod()
{
}
};
ThreadClass ^ objclass = gcnew ThreadClass;
ThreadStart^ mThread = gcnew ThreadStart(objclass,&objclass::ThreadClasMethod);
Thread^ newThread = gcnew Thread(mThread);
newThread->Start();
The ThreadState
and IsAlive
properties are used to get a thread state. But Microsoft doesn't recommend using those methods as thread synchronization. The System.Threading.Thread.Sleep
method is used to sleep the thread for current execution. We can't sleep another thread from thread function. The System.Threading.Timeout.Infinite
waits for an infinite level or when calls to other threads are returned. If System.Threading.Thread.Abort
is called, it will terminate.
In Managed threads, we will set thread priorities much like unmanaged threads. CLR assigned ThreadPriority.Normal
for default level. We can get or set the priority of any thread with the Thread.Priority
property. The Abort
method is used to destroy the managed threads permanently. When the Abort
method is called from the main method, a ThreadAbortException
is thrown.
Windows Forms with Controls
Microsoft introduced a new set of libraries in the .NET Framework with object oriented technology for creating the smart client applications in Windows. Windows Forms doesn't relate to existing technology for creating Windows like MFC, ATL or WTL. Windows Forms support the entire .NET Framework, and several languages share the same set of class libraries with .NET features. For example, MFC developers can get the features for .NET. Microsoft allows developers to mix both MFC and Windows forms into a single project. New MFC classes are used to access the .NET Windows Forms controls.
In our example, Windows Forms access between the multiple threads. The progress bar shows progress with different threads. Each progress bar has a separate button called a Thread
. If we click the individual buttons, the thread starts and runs separately. The Thread
starts in click event.
Thread^ newThread = gcnew Thread(gcnew ParameterizedThreadStart(&ThreadProc3 ));
newThread->Start(this);
The parameteterizedThreadStart
is used to pass the Windows Forms object to the thread function. The static
method calls the safe thread function. If developers want to change the status for Windows Forms control taken by a thread, we should declare a delegate.
delegate void ProgressBarCallback(System::Object ^obj);
This delegate passes a Windows Forms object. We change the status for each progressbar. If you want to invoke methods synchronously, you can call the following code:
static void SafeThread4(System::Object ^obj)
{
Form1 ^ob = (Form1^) obj;
if(ob->progressBar4->InvokeRequired)
{
ProgressBarCallback ^d = gcnew ProgressBarCallback(SafeThread4);
ob->Invoke(d,gcnew array<System::Object^>{ob});
}
else
{
for ( int i = 1; i <= 10; i++ )
{
ob->progressBar4->PerformStep();
Thread::Sleep( 80 );
}
}
}
Managed Threads and Exceptions
In .NET Framework 2.0, CLR handles unhandled exceptions in managed application.
Managed threads throws exception for the following situations:
ThreadAbortException
throws when user calls Abort method.
AppDomainUnloadedException
throws application domain in which the thread is executing is being unloaded.
- CLR throws when the host processes terminate the thread by throwing internal exception.
When I created the sample application, I tried to access the control class from thread function. But, I got the following exception:
static void ThreadProc1(System::Object ^obj)
{
Form1 ^ob = (Form1^) obj;
for ( int i = 0; i < 10; i++ )
{
ob->progressBar1->PerformStep();
Thread::Sleep( 0 );
}
}
When I execute the above code, I get the following exception:
System.InvalidOperationException was unhandled
Message="Cross-thread operation not valid:
Control 'progressBar1' accessed from a thread other than
the thread it was created on."
Source="System.Windows.Forms"
It gives the stack trace too.
Conclusion
Each application domain starts with at least a single thread. The System.Threading.Thread
class is used to create one or more number of threads in a managed environment. For a multithreaded application, the CPU switches between threads in a single process. If system uses multiple threads in multiprocessor environment, the thread switch changes between the multiple processors. Microsoft doesn't recommend mixing both managed and unmanaged threads. Managed threads are garbage collected. So, a developer doesn't care about cleaning up resources. So, we don't face the memory leak problem in managed threads. For creating the managed threads using best practices, read this.
History
- 17th January, 2006: Initial post