zoukankan      html  css  js  c++  java
  • C# 线程thread

    一、问题总结

     1. 在WinForm开发过程中用到线程时,往往需要在线程中访问线程外的控件,比如:设置textbox的Text值等等。如果直接访问UI控件会报出“从不是创建控件的线程访问它”错误。控件是在主线程中创建的(比如this.Controls.Add(...);),在其它线程直接访问主线程控件,与主线程发生线程冲突。

    解决方法:

    在控件响应函数中调用控件的Invoke方法,Invoke方法会顺着控件树向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。

    MSDN中说:
    获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
    如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。
    Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性 。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。   

    2. invoke表示同步,begininvoke表示异步。

    3.在使用invoke前,判断IsHandleCreated 此属性指示控件是否有与他关联的句柄,如果已经为控件分配了句柄,则为 true;否则为 false。

     加此判断可以避免在退出程序的时候,如果此时调用了invoke中的控件,就会出现错误“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。”

    二、代码举例

     1.线程访问主线程控件  

    using System;
    using System.Windows.Forms;
    using System.Threading;
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            private void Form1_Load(object sender, EventArgs e)
            {
    
            }
            private void btnStart_Click(object sender, EventArgs e)
            {
                Thread th = new Thread(new ThreadStart(DoWork));
                th.Start();         
    
            }     
            private void DoWork()
            {          
                ShowMsg("hello world");           
            }
    
            delegate void ShowMsgDelegate(string msg); 
            //普通委托
            private void ShowMsg(string msg)
            {
                if(lblMsg.InvokeRequired)
                {
                    ShowMsgDelegate showMsgDelegate = new ShowMsgDelegate(ShowMsg);
                    lblMsg.Invoke(showMsgDelegate, new object[] { msg });
                }
                else
                {
                    lblMsg.Text = msg;
                }           
    
            }
    
            //匿名代理
            private void ShowMsg2(string msg)
            {
                ShowMsgDelegate showMsgDelegate = delegate (string str)
                {
                    lblMsg.Text = str;
                };
                lblMsg.Invoke(showMsgDelegate, new object[] { msg });
    
            }
    
            //在C# 3.0及以后的版本中有了Lamda表达式,
            //像上面这种匿名委托有了更简洁的写法。
            private void ShowMsg3(string msg)
            {
                this.Invoke(new Action(() => {
                    lblMsg.Text = msg;
                }
                ));
            }
    
           
        }
    }
     
     private void ShowMsg(string msg, bool isOk)
            {
                if (this.IsHandleCreated)
                {
                    this.Invoke(new Action(() =>
                    {
                        lblMsg.Text = msg;
                        lblMsg.ForeColor = isOk ? Color.Green : Color.Red;                  
    
                    }));
                }
            }

    lambda写法

      private void button1_Click(object sender, EventArgs e)
            {
                Console.WriteLine("start");
                testThread =new Thread(() =>{
    
                    for(int i=0;i<20;i++)
                    {
                        Console.WriteLine(i);
                    }
                   
                });
                testThread.Start();
                Console.WriteLine("end");
            }

    执行结果:

    start
    end
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

  • 相关阅读:
    (转)怎样获得与激活Windows 7超级管理员权限
    (转) C代码优化方案
    英语词汇立体记忆 02
    (转)LUA和C之间的函数调用
    通过lua自带例子学习lua 01
    英语词汇立体记忆 01
    反射(类加载内存分析)
    反射(类加载器的作用)
    反射(动态创建对象操作属性)
    反射(分析类初始化)
  • 原文地址:https://www.cnblogs.com/ike_li/p/11327575.html
Copyright © 2011-2022 走看看