C # thread security issues caused by cross-thread calls of Form Controls (such as TextBox,

Source: Internet
Author: User

C # thread security issues caused by cross-thread calls of Form Controls (such as TextBox,

How to: make thread-safe calls to Windows Forms controls

Access to Windows Forms controls is not thread-safe in nature. If two or more threads operate on the status of a control, the control may be forced to enter an inconsistent state. Other thread-related bugs, such as contention and deadlocks, may also occur. It is important to ensure that controls are accessed in a thread-safe manner.

When the Invoke method is not used, it is unsafe for other threads that do not create a control to call the control. The following is an example of a non-thread-safe call.

        // This event handler creates a thread that calls a         // Windows Forms control in an unsafe way.        private void setTextUnsafeBtn_Click(            object sender,             EventArgs e)        {            this.demoThread =                 new Thread(new ThreadStart(this.ThreadProcUnsafe));            this.demoThread.Start();        }        // This method is executed on the worker thread and makes        // an unsafe call on the TextBox control.        private void ThreadProcUnsafe()        {            this.textBox1.Text = "This text was set unsafely.";        }

. NET Framework helps you detect the issue of using a non-thread-safe access control. When running an application in the debugger, if other threads that are not creating a control thread call the control, the debugger will throw an InvalidOperationException and display the following message: "It is never accessed by a thread that is not used to create the control name."

This exception occurs reliably during debugging and in some cases during runtime. This exception may occur when you debug applications written in. NET Framework before. NET Framework 2.0. We strongly recommend that you fix this issue when you discover it, but you can disable it by setting the checkforillegalcrossthreadcils attribute to false. (Not recommended)

Make thread-safe calls to Windows Forms controls

In the following code example, thread-safe calls are implemented in the ThreadProcSafe method executed by the background thread. If the InvokeRequired of the TextBox Control returns true, the ThreadProcSafe method creates an instance of SetTextCallback and passes the instance to the form's Invoke method. This makes the SetText method called by the thread that creates the TextBox Control and sets the Text attribute directly in the thread context.

       // This event handler creates a thread that calls a         // Windows Forms control in a thread-safe way.        private void setTextSafeBtn_Click(            object sender,             EventArgs e)        {               this.demoThread =                new Thread(new ThreadStart(this.ThreadProcSafe));               this.demoThread.Start();        }        // This method is executed on the worker thread and makes        // a thread-safe call on the TextBox control.        private void ThreadProcSafe()        {            this.SetText("This text was set safely.");        }
using System;using System.ComponentModel;using System.Threading;using System.Windows.Forms;namespace CrossThreadDemo{    public class Form1 : Form    {        // This delegate enables asynchronous calls for setting        // the text property on a TextBox control.        delegate void SetTextCallback(string text);        // This thread is used to demonstrate both thread-safe and        // unsafe ways to call a Windows Forms control.        private Thread demoThread = null;        // This BackgroundWorker is used to demonstrate the         // preferred way of performing asynchronous operations.        private BackgroundWorker backgroundWorker1;        private TextBox textBox1;        private Button setTextUnsafeBtn;        private Button setTextSafeBtn;        private Button setTextBackgroundWorkerBtn;        private System.ComponentModel.IContainer components = null;        public Form1()        {            InitializeComponent();        }        protected override void Dispose(bool disposing)        {            if (disposing && (components != null))            {                components.Dispose();            }            base.Dispose(disposing);        }        // This event handler creates a thread that calls a         // Windows Forms control in an unsafe way.        private void setTextUnsafeBtn_Click(            object sender,             EventArgs e)        {            this.demoThread =                 new Thread(new ThreadStart(this.ThreadProcUnsafe));            this.demoThread.Start();        }        // This method is executed on the worker thread and makes        // an unsafe call on the TextBox control.        private void ThreadProcUnsafe()        {            this.textBox1.Text = "This text was set unsafely.";        }        // This event handler creates a thread that calls a         // Windows Forms control in a thread-safe way.        private void setTextSafeBtn_Click(            object sender,             EventArgs e)        {            this.demoThread =                 new Thread(new ThreadStart(this.ThreadProcSafe));            this.demoThread.Start();        }        // This method is executed on the worker thread and makes        // a thread-safe call on the TextBox control.        private void ThreadProcSafe()        {            this.SetText("This text was set safely.");        }        // This method demonstrates a pattern for making thread-safe        // calls on a Windows Forms control.         //        // If the calling thread is different from the thread that        // created the TextBox control, this method creates a        // SetTextCallback and calls itself asynchronously using the        // Invoke method.        //        // If the calling thread is the same as the thread that created        // the TextBox control, the Text property is set directly.         private void SetText(string text)        {            // InvokeRequired required compares the thread ID of the            // calling thread to the thread ID of the creating thread.            // If these threads are different, it returns true.            if (this.textBox1.InvokeRequired)            {                    SetTextCallback d = new SetTextCallback(SetText);                this.Invoke(d, new object[] { text });            }            else            {                this.textBox1.Text = text;            }        }        // This event handler starts the form's         // BackgroundWorker by calling RunWorkerAsync.        //        // The Text property of the TextBox control is set        // when the BackgroundWorker raises the RunWorkerCompleted        // event.        private void setTextBackgroundWorkerBtn_Click(            object sender,             EventArgs e)        {            this.backgroundWorker1.RunWorkerAsync();        }                // This event handler sets the Text property of the TextBox        // control. It is called on the thread that created the         // TextBox control, so the call is thread-safe.        //        // BackgroundWorker is the preferred way to perform asynchronous        // operations.        private void backgroundWorker1_RunWorkerCompleted(            object sender,             RunWorkerCompletedEventArgs e)        {            this.textBox1.Text =                 "This text was set safely by BackgroundWorker.";        }        #region Windows Form Designer generated code        private void InitializeComponent()        {            this.textBox1 = new System.Windows.Forms.TextBox();            this.setTextUnsafeBtn = new System.Windows.Forms.Button();            this.setTextSafeBtn = new System.Windows.Forms.Button();            this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();            this.SuspendLayout();            //             // textBox1            //             this.textBox1.Location = new System.Drawing.Point(12, 12);            this.textBox1.Name = "textBox1";            this.textBox1.Size = new System.Drawing.Size(240, 20);            this.textBox1.TabIndex = 0;            //             // setTextUnsafeBtn            //             this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);            this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";            this.setTextUnsafeBtn.TabIndex = 1;            this.setTextUnsafeBtn.Text = "Unsafe Call";            this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);            //             // setTextSafeBtn            //             this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);            this.setTextSafeBtn.Name = "setTextSafeBtn";            this.setTextSafeBtn.TabIndex = 2;            this.setTextSafeBtn.Text = "Safe Call";            this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);            //             // setTextBackgroundWorkerBtn            //             this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);            this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";            this.setTextBackgroundWorkerBtn.TabIndex = 3;            this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";            this.setTextBackgroundWorkerBtn.Click += new System.EventHandler(this.setTextBackgroundWorkerBtn_Click);            //             // backgroundWorker1            //             this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);            //             // Form1            //             this.ClientSize = new System.Drawing.Size(268, 96);            this.Controls.Add(this.setTextBackgroundWorkerBtn);            this.Controls.Add(this.setTextSafeBtn);            this.Controls.Add(this.setTextUnsafeBtn);            this.Controls.Add(this.textBox1);            this.Name = "Form1";            this.Text = "Form1";            this.ResumeLayout(false);            this.PerformLayout();        }        #endregion        [STAThread]        static void Main()        {            Application.EnableVisualStyles();            Application.Run(new Form1());        }    }}

 

 

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.