欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2017年11月22日 10:12:23   作者:絳河  
下面小編就為大家分享一篇淺談C#跨線程調(diào)用窗體控件(比如TextBox)引發(fā)的線程安全問題,具有很好的參考價值,希望對大家有所幫助

如何:對 Windows 窗體控件進行線程安全調(diào)用

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

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

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

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

對 Windows 窗體控件進行線程安全調(diào)用

查詢控件的 InvokeRequired 屬性。

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

如果 InvokeRequired 返回 false,則直接調(diào)用控件。

在下面的代碼示例中,將在由后臺線程執(zhí)行的 ThreadProcSafe 方法中實現(xiàn)線程安全調(diào)用。 如果 TextBox 控件的 InvokeRequired 返回 true,則 ThreadProcSafe 方法會創(chuàng)建 SetTextCallback 的一個實例,并將該實例傳遞給窗體的 Invoke 方法。 這使得 SetText 方法被創(chuàng)建 TextBox 控件的線程調(diào)用,而且在此線程上下文中將直接設(shè)置 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#跨線程調(diào)用窗體控件(比如TextBox)引發(fā)的線程安全問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#刪除最后一個結(jié)尾逗號的方法

    C#刪除最后一個結(jié)尾逗號的方法

    這篇文章主要介紹了C#刪除最后一個結(jié)尾逗號的方法,涉及C#、操作字符串的技巧,簡單實用,非常具有實用價值,需要的朋友可以參考下
    2015-03-03
  • 深入講解C#編程中嵌套類型和匿名類型的定義與使用

    深入講解C#編程中嵌套類型和匿名類型的定義與使用

    這篇文章主要介紹了C#編程中嵌套類型和匿名類型的定義與使用,包括在SQL語句中使用匿名類型的方法,需要的朋友可以參考下
    2016-01-01
  • c#之用戶定義的數(shù)據(jù)類型轉(zhuǎn)換介紹

    c#之用戶定義的數(shù)據(jù)類型轉(zhuǎn)換介紹

    c#允許定義自己的數(shù)據(jù)類型,這意味著需要某些工具支持在自己的數(shù)據(jù)類型間進行數(shù)據(jù)轉(zhuǎn)換。方法是把數(shù)據(jù)類型轉(zhuǎn)換定義為相關(guān)類的一個成員運算符,數(shù)據(jù)類型轉(zhuǎn)換必須聲明是隱式或者顯式,以說明怎么使用它
    2014-01-01
  • C#實現(xiàn)一個控制臺的點餐系統(tǒng)

    C#實現(xiàn)一個控制臺的點餐系統(tǒng)

    這篇文章主要為大家詳細介紹了C#實現(xiàn)一個控制臺的點餐系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • C#延時函數(shù)的使用說明

    C#延時函數(shù)的使用說明

    這篇文章主要介紹了C#延時函數(shù)的使用說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • WPF中不規(guī)則窗體與WindowsFormsHost控件兼容問題的解決方法

    WPF中不規(guī)則窗體與WindowsFormsHost控件兼容問題的解決方法

    這篇文章主要介紹了WPF中不規(guī)則窗體與WindowsFormsHost控件兼容問題的解決方法,對比以往的解決方案,給出了一個具有普遍性的技巧,具有一定的借鑒價值,需要的朋友可以參考下
    2014-11-11
  • C#實現(xiàn)加密的幾種方法介紹

    C#實現(xiàn)加密的幾種方法介紹

    這篇文章介紹了C#實現(xiàn)加密的幾種方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • C#在Unity游戲開發(fā)中進行多線程編程的方法

    C#在Unity游戲開發(fā)中進行多線程編程的方法

    這篇文章主要介紹了C#在Unity游戲開發(fā)中進行多線程編程的方法,文中總結(jié)了Unity中使用多線程的幾種方式以及一款多線程插件的介紹,需要的朋友可以參考下
    2016-04-04
  • C#算法之各位相加

    C#算法之各位相加

    這篇文章介紹了C#算法之各位相加,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • C#影院售票系統(tǒng)畢業(yè)設(shè)計(4)

    C#影院售票系統(tǒng)畢業(yè)設(shè)計(4)

    這篇文章主要介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計,學習內(nèi)容是總結(jié)銷售信息的保存以及加載銷售信息,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2015-11-11

最新評論