SoFunction
Updated on 2025-03-06

Delegate Events for Multithreaded Communication in C#

When studying communication between c# threads, I found that there are about three traditional methods:

  1. Global variables. Since multiple processes under the same process share data space, using global variables is the easiest way, but remember to use volatile for limitations.
  2. Send messages between threads (this will be discussed later in the article).
  3. CEvent is an object in MFC. It can change the trigger state of CEvent to achieve communication and synchronization between threads. This is mainly a method to realize direct thread synchronization.

One method introduced in this article is one other than these three methods. The example in this article is to create a thread class, pass the value to the class where the Form is located through delegating events, and update the value in a control (Label) in the Form class.

The implementation function is relatively simple. The purpose is to implement this function. First post the code:

using System;
using ;
 
namespace ThreadsComm
{
 public delegate void ReadParamEventHandler(string sParam);
 class MyThread
 {
  public Thread thread1;
  private static ReadParamEventHandler OnReadParamEvent;
  public MyThread()
  {
   thread1 = new Thread(new ThreadStart(MyRead));
    = true;
   ();
  }
  public event ReadParamEventHandler ReadParam
  {
   add { OnReadParamEvent += new ReadParamEventHandler(value);}
   remove{ OnReadParamEvent -= new ReadParamEventHandler(value);}
  }
  protected void MyRead()
  {
   int i = 0;
   while (true)
   {
    (1000);
    i = i + 1;
    OnReadParamEvent(());//Trigger event   }
  }
 }
}

Among them

public event ReadParamEventHandler ReadParam
  {
   add { OnReadParamEvent += new ReadParamEventHandler(value);}
   remove{ OnReadParamEvent -= new ReadParamEventHandler(value);}
  }

This needs to be explained:

add The context keyword is used to define a custom event accessor that will be called when the client code subscribes to your event. If you provide a custom add accessor, you must also provide a remove accessor.

remove The context keyword is used to define a custom event accessor that is called when the client code unsubscribes to an event. If a custom remove accessor is provided, an add accessor must also be provided.

using System;
using ;
 
namespace ThreadsComm
{
 public partial class Form1 : Form
 {
  private static string param = "";
  public Form1()
  {
   InitializeComponent();
   MyThread thread1 = new MyThread();
    += ;
  }
 
  private void OnRead(string sParam)
  {
   param = sParam;
   Object[] list = { this,};
   (new EventHandler(LabelShow), list);
  }
  protected void LabelShow(Object o, EventArgs e)
  {
    = param;
  }
 }
}

Among them

 MyThread thread1 = new MyThread();
  += ;

is an event in the subscribed thread class.

 (new EventHandler(LabelShow), list);

Both the Invoke or BeginInvoke methods require a delegate object as a parameter. Delegation is similar to the address of a callback function, so the caller can marshall the function address that needs to be called to the interface thread through these two methods. If these methods contain code to change the state of the control, then since the interface thread is the final execution of this method, race conditions are avoided and unpredictable problems are avoided. If other threads directly operate the controls to which the interface thread belongs, race conditions will occur and unpredictable results will occur.

Using Invoke to complete a delegate method is similar to using the SendMessage method to send messages to interface threads, which is a synchronization method. That is to say, before the Invoke marshaling method is executed, the Invoke method will not return, so the caller thread will be blocked.

Use the BeginInvoke method to marshal a delegate method, similar to using PostMessage for communication, which is an asynchronous method. That is, the method will return immediately after marshaling, and will not wait for the end of the delegate method to be executed, and the caller thread will not be blocked. However, the caller can also use the EndInvoke method or other similar WaitHandle mechanism to wait for the completion of the asynchronous operation.

However, in terms of internal implementation, both Invoke and BeginInvoke use the PostMessage method, thereby avoiding the problems caused by SendMessage. The synchronization blocking of the Invoke method is accomplished by the WaitHandle mechanism.

Readers who want to experiment can build a winform project and use the above code to experiment.

The above is the detailed content of the delegation event for C# multi-threaded communication. For more information about C# multi-threaded delegation events, please pay attention to my other related articles!