Knowledge needs to be continuously accumulated, summarized and precipitated. Thinking and writing are the catalysts for growth

A unified thread cancellation model

Thread cancelling is very common in multi-threaded development, and Microsoft has been working on this. NET4.0 basic class library to introduce the unified thread cancellation model to support the thread cancellation function.

1. Cancel the token

The two important types in the thread unified cancellation model are CancellationToken and CancellationTokenSource. Each CancellationTokenSource object contains a “CancellationToken”. It is also easy to use to Cancel the Token by calling the Cancel() method of CancellationTokenSource. There’s a little chestnut down there

2. Interruptible threads

Here is a thread model process that can be interrupted

1. Design an interrupt function

A interruptible thread function template looks like this

Public class ThreadFuncObject {// Pass in the constructor to cancel the token. public ThreadFuncObject(CancellationToken token) { _token = token; } public voidDoWork() {// various function code...if(_token IsCancellationRequested) {/ / clean up work... // Simple processing is directreturnCan / /return; / / Suggestions to throw a cancel abnormal throw new OperationCanceledException (_token); } // Various function code... }}Copy the code
2. Create CancellationTokenSource object
CancellationTokenSource tokenSource = new CancellationTokenSource();
Copy the code
3. Start the thread
ThreadFuncObject obj = new ThreadFuncObject(tokenSource.Token);
Thread th = new Thread(obj.DoWork);
th.Start();
Copy the code
4. Cancel thread execution
tokenSource.Cancel();
Copy the code

The basic method of accessing the UI across threads

In the early days of desktop development, when making progress bars and other functions to notify UI updates, you often encounter cross-thread access to the UI. The error is that the control cannot be changed by the thread that created it.

In the.net Framework, all visual controls from the System. Windows. Forms. The Control class derived, considering the across threads the need of access Control, the Control class provides methods to complete the update interface across threads.

1, Control.invoke and BeginInvoke

// // Summary: // Executes the specified delegate on the thread that owns the underlying window handle for this control. The // // argument: // method: // contains the delegate for the method to be invoked in the thread context of the control. // // returns the result: // The return value of the delegate being invoked, or null if the delegate does not return a value. public object Invoke(Delegate method);Copy the code

The Invoke method takes a delegate that represents the method to be executed in the thread that created the control. In a real scenario to pass values to the UI, you can use the following overloading

// // Abstract: // Executes the specified delegate with the specified argument list on the thread that owns the control's underlying window handle. // // argument: // method: // A method delegate that takes the same number and type of arguments as those contained in the arGS argument. // // args: // An array of objects passed as arguments to the specified method. If the method has no arguments, the argument can be null. // // returns the result: // system.object, which contains the return value of the delegate being invoked; Null if the delegate does not return a value. public object Invoke(Delegate method, params object[] args);Copy the code

Use something like the following

private void ThreadMethod(Object info)
{
    Action<string> del = (msg) => lblInfo.Text = msg;
    lblInfo.Invoke(del,info);
}
Copy the code

Control.Invoke is a synchronous method that when a worker thread invokes this method to delegate a method to the UI thread, it must wait for the UI thread to finish executing the method before it can continue executing. If the UI thread is busy, the worker thread may wait a long time before being inactive. That may not make sense

BeginInvoke control. BeginInvoke is an asynchronous method, where a worker thread can pass a method to the UI thread to execute and proceed to the next task without waiting.

The UI thread is a single thread that updates the user interface and receives user responses. It extracts message processing from the message queue, and if a message takes too long to execute, the interface becomes unresponsive and feels dead. So long tasks are assigned to separate worker threads, and the UI thread just shows the user the results. UI threads should not have too many part-time jobs

2. Exit the desktop

Desktop (Windows Forms) applications are event-driven and should ensure that the user does not frequently click to start the thread that accesses the control. Because multiple threads access the same control at the same time, it may cause program instability and unexpected results. Thread synchronization can be controlled by controlling button state or thread state.

If closing the main form causes the main thread to exit, the worker thread is not finished. An ObjectDisposedException is thrown because the controls on the main form are destroyed, and the worker thread also contains code to access the controls.

The simplest way to Abort the worker thread is to set it as a background thread, which will exit when the main thread exits. Another way is to manually Abort the worker thread in the FormClosing event.

Write thread-safe controls

We can encapsulate multithreaded access into controls to simplify code for cross-thread access. For example, if the text property of the Lable label control is not directly accessible across threads, a new ThreadSafeLable class can be derived, like the following, so that the same code is used to access thread-safe controls across threads or not.

Public class ThreadSafeLable: Label {// Override string Text {get {return base.Text;
        }
        set
        {
            if(InvokeRequired) {Action<string> del = (MSG) => base.text = MSG; Invoke(del, value); }else// Plain call {base.text = value; }}}}Copy the code

In the project development, pay attention to encapsulate some such controls, which can simplify the multi-thread call code and improve the development efficiency of the project

Third, BackgroundWorker component

In fact, Microsoft provides a ready-made component for cross-thread access to the UI, that is the BackgroundWorker component, greatly simplifies the development of such programs. The event-based asynchronous invocation pattern tells you what to do and when. Support to report progress and cancel.





1. Working code

In the case of DoWork, the code that does the real work is here

2. Start the task

Call the RunWorkerAsync method of the BackgroundWorker component, which fires the DoWork event. This method has an overload that can pass an Object, which is received in DoWork via DoWorkEventArgs.Argument

3. Result fetch

BackgroundWorker component has a RunWorkerCompleted events RunWorkerCompletedEventArgs parameters include the following information:

Parameter properties describe
e.Result The result of the execution of the task
e.Error This is an Exception object, null if no Exception occurs during the execution of the work task, and reference the Exception object thrown if an Exception occurs
e.Cancelled This property is True if the user cancels the action before the work task completes, and False otherwise

4. Cancel the task

The BackgroundWorker component has a CancelAsync method. Calling this method causes the BackgroundWorker component’s read-only CancellationPending to be True, which can then be checked in DoWork.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bw = sender as BackgroundWorker;
    ifCancellationPending)// If the user cancels the operation {e.cancel =true; // The result will be passed to the RunWorkerCompleted eventreturn; // You still need to manually submit the end task} //... }Copy the code

5. Progress report

The BackgroundWorker component has a ProgressChanged event. Calling the ReportProgress method of the BackgroundWorker component at an appropriate place in the DoWork event handling code fires the ProgressChanged event. In addition to reporting progress, ReportProgress can also report an object via its overloading, usually describing information.

The Special handling in the ProgressChanged event is done with the thread synchronization context, allowing direct access to the controls on the form without cross-threading concerns.

Four, etc.

I’ve read a lot of things before, and I forget them. We’re moving soon, and if we can’t put it in our head, we can’t take it with us. Every move for a few books to pay more moving fees, melancholy. (Books are the heaviest things without electricity.)