Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C++/CLI

Threads with Windows Forms Controls in Managed C++

Rate me:
Please Sign up or sign in to vote.
3.33/5 (12 votes)
17 Jan 2006CPOL4 min read 97.2K   1.9K   22   6
This article explains Managed Threads with Windows Forms Controls

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:

C++
ref class ThreadClass
{
public:
   static void ThraedClassMethod()
   {
      /// Do work 
   }
};

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.

C++
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.

C++
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:

C++
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:

C++
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:

C++
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India
Selvam has worked on several technologies like Java, Python, Big data, VC++, MFC, Windows API and Weblogic server. He takes a lot of interest in reading technical articles and enjoys writing them too. He has been awarded as a Microsoft Community Star in 2004, MVP in 2005-06, SCJP 5.0 in 2009, Microsoft Community Contributor(MCC) 2011.

Big Data
o Google Professional Data Engineer 2021
o Confluent Certified Developer for Apache Kafka 2020
o Datastax Apache Cassandra 3.x Developer Associate Certification 2020
✓ Cloud
o Google Professional Cloud Architect 2021
o Microsoft Certified: Azure Solutions Architect Expert 2020
o AWS Certified Solutions Architect - Associate 2020
✓ Oracle Certified Master, Java EE 6 Enterprise Architect (OCMEA) 2018

Github : https://github.com/selvamselvam
Web site: http://www.careerdrill.com
Linkedin: https://www.linkedin.com/in/selvamselvam/

Comments and Discussions

 
QuestionLong time ago but works Pin
Member 1319775214-Feb-21 4:49
Member 1319775214-Feb-21 4:49 
GeneralMy vote of 1 Pin
wincberg16-Jan-15 8:42
wincberg16-Jan-15 8:42 
AnswerUnblocking solution. Pin
Member 1021633618-Aug-13 2:39
Member 1021633618-Aug-13 2:39 
AnswerA solution [modified] Pin
betmax8-Sep-06 21:23
betmax8-Sep-06 21:23 
I think that the solution would be to rewrite it like:

delegate void ProgressBarCallback(System::Object ^obj);

static void ToUpdateProgressBar1(System::Object ^obj)
{
 Form1 ^ob = (Form1^) obj;
 ob->progressBar1->PerformStep();
}

static void SafeThread1(System::Object ^obj)
{
 Form1 ^ob = (Form1^) obj;
 ProgressBarCallback ^d;

 if(ob->progressBar1->InvokeRequired)
	d = gcnew ProgressBarCallback(ToUpdateProgressBar1);

 for(int i=1; i<=10; i++)
	{
	Thread::Sleep(80);

	//Invoke the progress bar
	ob->Invoke(d,gcnew array<System::Object^>{ob});
	}
}

Thus yes it works as it is expected, although also produces errors in the end... Sigh | :sigh:


Excepción no controlada del tipo 'System.ObjectDisposedException' en System.Windows.Forms.dll

Información adicional: No se puede obtener acceso al objeto eliminado.

QuestionThe operating system is hung here Pin
betmax8-Sep-06 20:54
betmax8-Sep-06 20:54 
QuestionIt does not work well [modified] Pin
betmax8-Sep-06 20:10
betmax8-Sep-06 20:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.