1. 程式人生 > >C#多執行緒非同步訪問winform中控制元件

C#多執行緒非同步訪問winform中控制元件

我們在做winform應用的時候,大部分情況下都會碰到使用多執行緒控制介面上控制元件資訊的問題。然而我們並不能用傳統方法來做這個問題,下面我將詳細的介紹。

      首先來看傳統方法:

     public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(ThreadFuntion);
            thread.IsBackground = true;
            thread.Start();
        }
        private void ThreadFuntion()
        {
            while (true)
            {
                this.textBox1.Text = DateTime.Now.ToString();
                Thread.Sleep(1000);
            }
        }
    }

       執行這段程式碼,我們會看到系統丟擲一個異常:Cross-thread operation not valid:Control 'textBox1' accessed from a thread other than the thread it was created on. 這是因為.net 2.0以後加強了安全機制,不允許在winform中直接跨執行緒訪問控制元件的屬性。那麼怎麼解決這個問題呢,下面提供幾種方案。

      第一種方案,我們在Form1_Load()方法中加一句程式碼:

      private void Form1_Load(object sender, EventArgs e)
       {
            Control.CheckForIllegalCrossThreadCalls = false;
            Thread thread = new Thread(ThreadFuntion);
            thread.IsBackground = true;
            thread.Start();
        }
      加入這句程式碼以後發現程式可以正常運行了。這句程式碼就是說在這個類中我們不檢查跨執行緒的呼叫是否合法(如果沒有加這句話執行也沒有異常,那麼說明系統以及預設的採用了不檢查的方式)。然而,這種方法不可取。我們檢視CheckForIllegalCrossThreadCalls 這個屬性的定義,就會發現它是一個static的,也就是說無論我們在專案的什麼地方修改了這個值,他就會在全域性起作用。而且像這種跨執行緒訪問是否存在異常,我們通常都會去檢查。如果專案中其他人修改了這個屬性,那麼我們的方案就失敗了,我們要採取另外的方案。

      下面來看第二種方案,就是使用delegate和invoke來從其他執行緒中控制控制元件資訊。網上有很多人寫了這種控制方式,然而我看了很多這種帖子,表明上看來是沒有什麼問題的,但是實際上並沒有解決這個問題,首先來看網路上的那種不完善的方式:

public partial class Form1 : Form
    {
        private delegate void FlushClient();//代理
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(CrossThreadFlush);

             thread.IsBackground=true;
            thread.Start();
        }

        private void CrossThreadFlush()
        {
            //將代理繫結到方法
            FlushClient fc = new FlushClient(ThreadFuntion);
            this.BeginInvoke(fc);//呼叫代理
        }
        private void ThreadFuntion()
        {
            while (true)
            {
                this.textBox1.Text = DateTime.Now.ToString();
                Thread.Sleep(1000);
            }
        }
    }

       使用這種方式我們可以看到跨執行緒訪問的異常沒有了。但是新問題出現了,介面沒有響應了。為什麼會出現這個問題,我們只是讓新開的執行緒無限迴圈重新整理,理論上應該不會對主執行緒產生影響的。其實不然,這種方式其實相當於把這個新開的執行緒“注入”到了主控制執行緒中,它取得了主執行緒的控制。只要這個執行緒不返回,那麼主執行緒將永遠都無法響應。就算新開的執行緒中不使用無限迴圈,使可以返回了。這種方式的使用多執行緒也失去了它本來的意義。

       現在來讓我們看看推薦的解決方案:

public partial class Form1 : Form
    {
        private delegate void FlushClient();//代理
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(CrossThreadFlush);
            thread.IsBackground = true;
            thread.Start();
        }

        private void CrossThreadFlush()
        {
            while (true)
            {
                //將sleep和無限迴圈放在等待非同步的外面
                Thread.Sleep(1000);
                ThreadFunction();
            }
        }
        private void ThreadFunction()
        {
            if (this.textBox1.InvokeRequired)//等待非同步
            {
                FlushClient fc = new FlushClient(ThreadFunction);
                this.Invoke(fc);//通過代理呼叫重新整理方法
            }
            else
            {
                this.textBox1.Text = DateTime.Now.ToString();
            }
        }
    }

       執行上述程式碼,我們可以看到問題已經被解決了,通過等待非同步,我們就不會總是持有主執行緒的控制,這樣就可以在不發生跨執行緒呼叫異常的情況下完成多執行緒對winform多執行緒控制元件的控制了。

相關推薦

C#執行非同步訪問winform控制元件

我們在做winform應用的時候,大部分情況下都會碰到使用多執行緒控制介面上控制元件資訊的問題。然而我們並不能用傳統方法來做這個問題,下面我將詳細的介紹。       首先來看傳統方法:      public partial class Form1 : Form    

WPF執行直接訪問介面的控制元件的解決方式

WPF:Dispatcher.Invoke方法,只有在其上建立 Dispatcher的執行緒才可以直接訪問DispatcherObject。若要從不同於在其上建立 DispatcherObject的執行緒的某個執行緒訪問 DispatcherObject,請對與 DispatcherObject關聯的

C# 使用執行訪問winform控制元件

 我們在做winform應用的時候,大部分情況下都會碰到使用多執行緒控制介面上控制元件資訊的問題。然而我們並不能用傳統方法來做這個問題,下面我將詳細的介紹。 首先來看傳統方法: 1 public partial class Form1 : Form 2 { 3

C# 執行 非同步

一、基本概念 1、程序 首先開啟工作管理員,檢視當前執行的程序: 從工作管理員裡面可以看到當前所有正在執行的程序。那麼究竟什麼是程序呢? 程序(Process)是Windows系統中的一個基本概念,它包含著一個執行程式所需要的資源。一個正在執行的應用程式在作業

Java併發程式設計(03):執行併發訪問,同步控制

本文原始碼:[GitHub·點這裡](https://github.com/cicadasmile/java-base-parent) || [GitEE·點這裡](https://gitee.com/cicadasmile/java-base-parent) # 一、併發問題 多執行緒學習的時候,要面

C#執行訪問winform控制元件

方法一:System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;  不推薦使用這種方式,禁止編譯器對跨執行緒訪問做檢查的方式實現。 方法二:使用delegate和invoke private

C#執行程式設計筆記(5.5)-處理非同步操作的異常

近來在學習Eugene Agafonov編寫的《C#多執行緒程式設計實戰》(譯),做些筆記也順便分享一下^-^本篇將描述在C#中使用非同步函式時如何處理異常。我們將學習對多個並行的非同步操作使用await時如何聚合異常。using System; using System.T

2017.10.12 C#執行非同步的區別

最近在寫個多執行緒處理的程式,又重新溫習了一下相關知識,記錄在這裡。 C#多執行緒與非同步的區別 原文地址:http://kb.cnblogs.com/page/116095/ 多執行緒和非同步操作的異同   多執行緒和非同步操作兩者都可以達到避免呼叫執行緒阻塞的目的,從而提高軟體

C++執行的future(期望)

Providers std::promise 和std::future配合使用,給std::future傳遞期望值,下面是最簡單的一個用法: #include <iostream> #include <functional> #include <

C# 執行呼叫靜態方法或者靜態例項的同一個方法-方法內部的變數是執行安全的

 C#  多執行緒呼叫靜態方法或者靜態例項中的同一個方法-方法內部的變數是執行緒安全的       using System;using System.Threading;using System.Threading.Tasks;using Sys

winform執行時可以拖動視窗(C#執行

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; u

C# 基礎(十四)C#單例模式:首先介紹 單執行執行、加鎖 單例模式。然後介紹單例模式的執行同步:執行有序訪問共享記憶體。

一、簡介 本篇文章將介紹如何使用單例模式,也就是類的例項化,在整個專案的生命週期內,只例項化一次。在單例模式中,往往可以看到如SourceCode.cs:這樣的結構的。 SourceCode.cs: public class Singleton { private static

C#執行之Parallel 類似於for的continue,break的方法

C#多執行緒之Parallel中 類似於for的continue,break的方法 好久沒寫東西了,終於找到點知識記錄下。。。 利用ParallelLoopState物件來控制Parallel.For函式的執行,ParallelLoopState物件是由執行時在後臺建立的: Parall

最簡單的實現Linux C++執行的互斥訪問

#include <stdlib.h> #include <string.h> #include <iostream> #include <unistd.h> #include <errno.h> #include <pthrea

C#執行程式設計筆記(5.2)-在lambda表示式使用await操作符

近來在學習Eugene Agafonov編寫的《C#多執行緒程式設計實戰》(譯),做些筆記也順便分享一下^-^using System; using System.Threading.Tasks; using System.Threading; namespace 在Lam

C#執行 && 執行lock用法的經典例項

程序(Process)是Windows系統中的一個基本概念,它包含著一個執行程式所需要的資源。一個正在執行的應用程式在作業系統中被視為一個程序,程序可以包括一個或多個執行緒。執行緒是作業系統分配處理器時間的基本單元,在程序中可以有多個執行緒同時執行程式碼。程序之間是相對獨立的

關於C++執行程式簡單型別(int/bool)的安全性

關於這個問題,很少有聽到權威的解答。偶這裡也只是收集各處資料,以嘗試對今後寫出高質量的程式碼做一定的保證。 通常會聯想到這個問題應該跟CPU架構相關。CSDN上也有人做了實驗。根據其結論,在x86上,對1位元組byte/2位元組word/4位元組int型別的讀寫操作都是原子

C# 實現的執行非同步Socket資料包接收器框架

幾天前在博問中看到一個C# Socket問題,就想到筆者2004年做的一個省級交通流量接收伺服器專案,當時的基本求如下: 接收自動觀測裝置通過無線網絡卡、Internet和Socket上報的交通量資料包 全年365*24執行的自動觀測裝置5分鐘上報一次觀測資料,每筆記錄約

C#執行非同步的區別

原文地址:http://kb.cnblogs.com/page/116095/  隨著擁有多個硬執行緒CPU(超執行緒、雙核)的普及,多執行緒和非同步操作等併發程式設計方法也受到了更多的關注和討論。本文主要是想與園中各位高手一同探討一下如何使用併發來最大化程式的效能。   多執行緒和非同步操作的異同  

C#執行非同步委託/呼叫

C#非同步呼叫(Asynchronou Delegate) C#非同步呼叫獲取結果方法:主要有三種,也可以說是四種(官方說四種,電子書說三種),官方在MSDN上已經有詳細的說明: 連結 需要了解到獲取非同步執行的返回值,意味著你需要呼叫Delegate的BeginIn