Multi-thread journey 7-GUI thread model, message delivery (post) and processing (before IOS development)

Source: Internet
Author: User
Message-based GUI Architecture

In the past few days, the GUI architecture of most programming language platforms has hardly changed. Although there are some differences in details, such as functional and programming style, most of them adopt the same architecture to respond to user input and redraw the screen. This architecture can be summarized as "Single-threaded and message-based ".

 

 
Message msg;While(GetMessage(msg)){    TranslateMessage(msg);    DispatchMessage(msg);}

 

 

 

This code can be called a message loop. In this loop, the execution sequence is sequential. A GetMessage can only be executed after the previous GetMessage is executed.

Take WPF or WindowsForm as an example. Each thread creates at least one window with a message queue, and one of the tasks of this thread is to process various messages in the queue. As long as Application. Run is called in the Application, the thread that executes this method is assigned this task by default. All subsequent GUI events, such as user-triggered events (click the button, close the window, etc.), system-triggered events (re-painting the window, resize, etc ), as well as specific events of custom components in the application, the corresponding messages will be delivered to this message queue for implementation. This means that after the run is called, most of the subsequent work is generated by the event processor in response to GUI events.

 

 

 

GUI thread

The Gui thread is responsible for retrieving (get) and dispatching (dispatch) messages, and also for describing the interface. If the GUI thread is blocked in the delivery and processing of messages, then the message will accumulate in the message queue and wait for the GUI thread to return to the message queue.

If the block is a long operation, such as downloading an object for 10 seconds, the user cannot perform any operation within 10 seconds, because the thread cannot obtain new messages for processing.

This is why MsgWaitForMultipleObjects exists in Windows. This API allows the thread to still run the message loop while waiting. In. NET, you don't even have this option.

Complex re-entry issues must be taken into account during message delivery. It is difficult to ensure that other GUI events can be securely distributed to respond to messages when an event processor is congested.

Therefore, a relatively easy solution is that only the code in the GUI thread can manipulate the GUI control, other data and computation required when updating the GUI must be completed in other threads, rather than on the GUI thread.

 

 

This usually means that the work is transferred to the thread pool for completion, and then the results are merged back to the GUI thread after the results are obtained. This is the two classes we will introduce next.

 

SynchronizationContext and BackgroundWorker

SynchronizationContext synchronizes scheduling operations between different threads, and posts the results of some asynchronous operations back to the GUI thread.

 

Implementation of DispatcherSynchronizationContext in WPF

public  override  void  Post(SendOrPostCallback  d,  object  state) {     _dispatcher.Beginlnvoke(DispatcherPriority.Normal,  d,  state);     }     public  override  void  Send(SendOrPostCallback  d,  object  state)     {     _dispatcher.lnvoke(DispatcherPriority.Normal,  d,  state);} 

 

In some cases, for example, in the console, we cannot get the SynchronizationContext instance through the Current attribute of the SynchronizationContext class. We have wrapped this method.

private static AsyncCallback SyncContextCallback(AsyncCallback callback) {   // Capture the calling thread's SynchronizationContext-derived object   SynchronizationContext sc = SynchronizationContext.Current;    // If there is no SC, just return what was passed in   if (sc == null) return callback;    // Return a delegate that, when invoked, posts to the captured SC a method that    // calls the original AsyncCallback passing it the IAsyncResult argument   return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);}

 

 

This method converts a common AsyncCallback method to a special AsyncCallback method, which is called through SynchronizationContext. In this way, no matter whether the thread model contains a GUI thread or not, it can be called correctly.

internal sealed class MyWindowsForm : Form {   public MyWindowsForm() {      Text = "Click in the window to start a Web request";      Width = 400; Height = 100;   }   protected override void OnMouseClick(MouseEventArgs e) {      // The GUI thread initiates the asynchronous Web request       Text = "Web request initiated";      var webRequest = WebRequest.Create("http://Wintellect.com/");      webRequest.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webRequest);      base.OnMouseClick(e);   }    private void ProcessWebResponse(IAsyncResult result) {      // If we get here, this must be the GUI thread, it's OK to update the UI      var webRequest = (WebRequest)result.AsyncState;      using (var webResponse = webRequest.EndGetResponse(result)) {         Text = "Content length: " + webResponse.ContentLength;      }   }}

This is actually the basic principle of AsyncOperationManager.

public  static  class  AsyncOperationManager {     public  static  SynchronizationContext  {  getj  setj  }     public  static  AsyncOperation  CreateOperation( object  userSuppliedState ) ; }

 

BackGroundWorker is a high-level abstraction built on the basis of the above mentioned. It provides a standard definition for some of the most common operations in GUI programs. There are three events:

DoWork, ProgressChanged, and RunWorkerCompleted

When the RunWorkerAsync method is called in a program, the DoWork event processing is started. When the ReportProgress method is called during event processing, the event processing of the ProgressChanged event is started, when the DoWork event processing is complete, the RunWorkerCompleted event is triggered.

    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();            backgroundWorker1.WorkerReportsProgress = true;            backgroundWorker1.WorkerSupportsCancellation = true;        }        private void startAsyncButton_Click(object sender, EventArgs e)        {            if (backgroundWorker1.IsBusy != true)            {                // Start the asynchronous operation.                backgroundWorker1.RunWorkerAsync();            }        }        private void cancelAsyncButton_Click(object sender, EventArgs e)        {            if (backgroundWorker1.WorkerSupportsCancellation == true)            {                // Cancel the asynchronous operation.                backgroundWorker1.CancelAsync();            }        }        // This event handler is where the time-consuming work is done.  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)        {            BackgroundWorker worker = sender as BackgroundWorker;            for (int i = 1; i <= 10; i++)            {                if (worker.CancellationPending == true)                {                    e.Cancel = true;                    break;                }                else                {                    // Perform a time consuming operation and report progress.                    System.Threading.Thread.Sleep(500);                    worker.ReportProgress(i * 10);                }            }        }        // This event handler updates the progress.  private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)        {            resultLabel.Text = (e.ProgressPercentage.ToString() + "%");        }        // This event handler deals with the results of the background operation.  private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)        {            if (e.Cancelled == true)            {                resultLabel.Text = "Canceled!";            }            else if (e.Error != null)            {                resultLabel.Text = "Error: " + e.Error.Message;            }            else            {                resultLabel.Text = "Done!";            }        }    }
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.