国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

淺談C#跨線程調用窗體控件(比如TextBox)引發的線程安全問題

2019-10-29 21:07:21
字體:
來源:轉載
供稿:網友

如何:對 Windows 窗體控件進行線程安全調用

訪問 Windows 窗體控件本質上不是線程安全的。 如果有兩個或多個線程操作某一控件的狀態,則可能會迫使該控件進入一種不一致的狀態。 還可能會出現其他與線程相關的 Bug,例如爭用情況和死鎖。 確保以線程安全方式訪問控件非常重要。

在未使用 Invoke 方法的情況下,從不是創建某個控件的線程的其他線程調用該控件是不安全的。 以下非線程安全的調用的示例。

// 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 可幫助您檢測以非線程安全方式訪問控件這一問題。 在調試器中運行應用程序時,如果一個不是創建某個控件的線程的其他線程調用該控件,則調試器會引發一個 InvalidOperationException,并顯示以下消息:“從不是創建控件控件名稱 的線程訪問它。”

此異常在調試期間和運行時的某些情況下可靠地發生。 在調試以 .NET Framework 2.0 版之前的 .NET Framework 編寫的應用程序時,可能會出現此異常。 我們強烈建議您在發現此問題時進行修復,但您可以通過將 CheckForIllegalCrossThreadCalls 屬性設置為 false 來禁用它。(不推薦)

對 Windows 窗體控件進行線程安全調用

查詢控件的 InvokeRequired 屬性。

如果 InvokeRequired 返回 true,則使用實際調用控件的委托來調用 Invoke。

如果 InvokeRequired 返回 false,則直接調用控件。

在下面的代碼示例中,將在由后臺線程執行的 ThreadProcSafe 方法中實現線程安全調用。 如果 TextBox 控件的 InvokeRequired 返回 true,則 ThreadProcSafe 方法會創建 SetTextCallback 的一個實例,并將該實例傳遞給窗體的 Invoke 方法。 這使得 SetText 方法被創建 TextBox 控件的線程調用,而且在此線程上下文中將直接設置 Text 屬性。

// 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());  } }}

以上這篇淺談C#跨線程調用窗體控件(比如TextBox)引發的線程安全問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 康定县| 三河市| 长汀县| 定兴县| 澄江县| 双鸭山市| 宜宾县| 富民县| 肃南| 开阳县| 福海县| 鹤岗市| 衡阳市| 张掖市| 仁寿县| 安阳市| 海阳市| 甘洛县| 吉林省| 张北县| 沽源县| 通城县| 开化县| 荆门市| 锡林郭勒盟| 西充县| 色达县| 临桂县| 神木县| 托克托县| 巴东县| 浏阳市| 竹溪县| 新津县| 九寨沟县| 崇明县| 岳普湖县| 岫岩| 临颍县| 张家界市| 屯门区|