[C#参考]UI和线程(一)

时间:2023-01-08 10:27:45

Windows是一个多任务的系统,如果你使用的是windows 2000及其以上版本,你可以通过任务管理器查看当前系统运行的程序和进程。

什么是进程呢?当一个程序开始运行时,它就是一个进程,进程所指包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的,线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

一 关于Thread的说明

在.net framework class library中,所有与多线程机制应用相关的类都是放在System.Threading命名空间中的。其中提供Thread类用于创建线程,ThreadPool类用于管理线程池等等,此外还提供解决了线程执行安排,死锁,线程间通讯等实际问题的机制。如果你想在你的应用程序中使用多线程,就必须包含这个类。Thread类有几个至关重要的方法,描述如下:

  • Start():启动线程
  • Sleep(int):静态方法,暂停当前线程指定的毫秒数
  • Abort():通常使用该方法来终止一个线程
  • Suspend():该方法并不终止未完成的线程,它仅仅挂起线程,以后还可恢复。
  • Resume():恢复被Suspend()方法挂起的线程的执行

线程入口使程序知道该让这个线程干什么事在C#中,线程入口是通过ThreadStart代理(delegate)来提供的你可以把ThreadStart理解为一个函数指针,指向线程要执行的函数当调用 Thread.Start()方法后,线程就开始执行ThreadStart所代表或者说指向的函数。 ThreadState在各种情况下的可能取值如下:

  • Aborted:线程已停止
  • AbortRequested:线程的Thread.Abort()方法已被调用,但是线程还未停止
  • Background:线程在后台执行,与属性Thread.IsBackground有关
  • Running:线程正在正常运行
  • Stopped:线程已经被停止
  • StopRequested:线程正在被要求停止
  • Suspended:线程已经被挂起(此状态下,可以通过调用Resume()方法重新运行)
  • SuspendRequested:线程正在要求被挂起,但是未来得及响应
  • Unstarted:未调用Thread.Start()开始线程的运行
  • WaitSleepJoin:线程因为调用了Wait(),Sleep()或Join()等方法处于*状态

二 Winform中使用的thread

首先可以看看最直接的方法,也是.net 1.0下支持的方法。但请注意的是,此方法在.net 2.0以后就已经是一种错误的方法了。

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

这段code在vs2005或者2008上都抛出异常 :Cross-thread operation not valid:Control 'textBox1' accessed from a thread other than the thread it was created on . 这是因为.net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性。那么怎么解决这个问题呢,下面提供几种方案。

第一种方案: 在Thread创建之前,将Control.CheckForIllegalCrossThreadCalls 设为 false。 此代码告诉编译器:在这个类中我们不检查跨线程的调用是否合法(如果没有加这句话运行也没有异常,那么说明系统以及默认的采用了不检查的方式)。然而,这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。而且像这种跨线程访问是否存在异常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了,我们要采取另外的方案。

第二种方案:

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//子线程计数器
private int counter; public Form1()
{
InitializeComponent();
}//Form1 private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(StartWorkFromUIThread));
//设置线程为后台线程,这样的话前台UI线程死亡时它也跟着死亡
//如果设置为前台线程,UI线程死亡后这个线程是不会死亡的,所以即使关闭了窗口,程序也不会结束。因为有前台线程在运行
thread.IsBackground = true;
thread.Start(); }//button1_Click //子线程执行序
private void StartWorkFromUIThread()
{
while(true)
{
if(this.InvokeRequired)
{
//Invoke的作用就是让后面的函数到主线程中去执行
//所以在Invoke里面的函数中,不能有Sleep,这样会卡死界面
BeginInvoke(new EventHandler(RunsOnWorkerThread), null);
}
else
{
RunsOnWorkerThread(this,null);
}
Thread.Sleep();
} }//StartWorkFromUIThread //要在主线程中做相应的工作
private void RunsOnWorkerThread(object sender, EventArgs e)
{
//计数器计算调用的次数
counter++;
lblTimeShow.Text = DateTime.Now.ToString()+ " " + counter.ToString();
}//RunsOnWorkerThread }//class
}

上面代码知识点的解释:

InvokeRequired,获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。上面的this就是拥有控件的窗体,这句话就是测试一下当前的位置是不是在UI线程中。不是的话返回true,是的话返回false。

如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。

如果不需要 Invoke(调用发生在同一线程上),或者如果控件是在另一个线程上创建的但尚未创建控件的句柄,则 InvokeRequired 可以返回 false。


总结:

在Winform多线程中,由于子线程是不能直接操作UI线程中的控件的,所以利用Invoke(函数,参数),让子线程能调用一个函数完成对控件的操作,当然这个函数也就会在UI线程中运行,这个函数中不能有过多的计算和sleep的出现,否则会阻塞UI线程,界面卡死。

Invoke是很好理解的,UI线程(主线程)可以new一个新的子线程,然后告诉它去执行哪个函数;同样的,子线程可以起让UI主线程去执行一个函数。

通过上叙代码,可以看到问题已经被解决了,通过等待异步,我们就不会总是持有主线程的控制,这样就可以在不发生跨线程调用异常的情况下完成多线程对winform多线程控件的控制了。

[C#参考]UI和线程(一)的更多相关文章

  1. [置顶] 使用严苛模式打破Android4.0以上平台应用中UI主线程的“独断专行”

    传送门 ☞ *的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 已经有好一段时间没有关注Android应用方面的事情了:)最近单位来了一个Androi ...

  2. handler更新UI主线程

    示例:下面代码的功能是修改UI主线程TextView的内容 public class MainActivity extends Activity { private Button btn_start; ...

  3. android UI跨线程操作

    android应用程序也是单线程程序,主线程为UI线程. android 线程是非安全的,即不要在子线程中更新 UI. public class MasterActivity extends Acti ...

  4. UI的线程问题:单线程原因及更新UI的四种方式

    1.UI线程为什么设计为单线程? UI控件的操作不是线程安全的,对于多线程并发访问的时候,如果使用加锁机制会导致: UI控件的操作变得很复杂. 加锁的操作必定会导致效率下降. 所以android系统在 ...

  5. 创建UI的线程才能访问UI,那么怎样才算访问UI呢

    只有创建UI元素的线程(主线程又叫UI线程)才能访问UI元素.在UI线程中工作,不会有这个问题. 在后台线程中,如果直接访问UI元素,会抛出 “调用线程无法访问此对象,因为另一个线程拥有该对象” 异常 ...

  6. QT UI 线程为什么卡死?

    我的工程是由三个线程处理不同任务构成的,其中UI用于显示,还有数据处理和数据接收发送线程. 在运行的过程中发现由于数据处理线程不及时,超过了设定的100ms,导致UI卡死,几个周期后又恢复,接着又卡死 ...

  7. android 更新uI主线程

    http://www.cnblogs.com/wenjiang/p/3180324.html handleMessage 好用

  8. c#多线程(UI线程,控件显示更新) Invoke和BeginInvoke 区别

    如果只是直接使用子线程访问UI控件,直接看内容三,如果想深入了解从内容一看起. 一.Control.Invoke和BeginInvoke方法的区别 先上总结: Control.Invoke 方法 (D ...

  9. [转] c#多线程(UI线程,控件显示更新) Invoke和BeginInvoke 区别

    如果只是直接使用子线程访问UI控件,直接看内容三,如果想深入了解从内容一看起. 一.Control.Invoke和BeginInvoke方法的区别 先上总结: Control.Invoke 方法 (D ...

随机推荐

  1. Python for Infomatics 第13章 网页服务四(译)

    这几天因为其他事务,打断了自己的学习计划,今天继续我的翻译,避免又中途而废. 注:文章原文为Dr. Charles Severance 的 <Python for Informatics> ...

  2. 单片机上的发光二极管&lpar;LED灯&rpar;

    LED(light-emitting diode),即发光二极管,俗称 LED 小灯,它的种类很多,参数也不尽相同,我们板子上用的是普通的贴片发光二极管.这种二极管通常的正向导通电压是 1.8V到 2 ...

  3. &lpar; ̄y&bigtriangledown; ̄&rpar;~ 智能手机II

    ( ̄y▽ ̄)~ 智能手机II TimeLimit: 3000/1000 MS (Java/Others)  MenoryLimit: 32768/32768 K (Java/Others) 64-bi ...

  4. &lbrack;Angular Tutorial&rsqb; 7-XHRs &amp&semi; Dependency Injection

    我们受够了在应用中用硬编码的方法嵌入三部电话!现在让我们用Angular内建的叫做$http的服务来从我们的服务器获取更大的数据集吧.我们将会使用Angular的依赖注入来为PhoneListCtrl ...

  5. C语言缓冲区(缓存)详解

    缓冲区又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区.缓冲区根据其对应的是输入设备还是输出设备,分为输 ...

  6. jakarta-taglibs-standard-1&period;1&period;0查找下载

  7. 1、Shiro 安全框架与Spring 整合详解

    Apache Shiro 是一个安全认证框架,和 Spring Security 相比,在于他使用了比较简洁易懂的认证和授权方式.其提供的 native-session(即把用户认证后的授权信息保存在 ...

  8. org&period;springframework&period;web&period;util&period;Log4jWebConfigurer

    org.springframework.web.util.Log4jWebConfigurer @Deprecated Deprecated. as of Spring 4.2.1, in favor ...

  9. C&num;安全加密类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.S ...

  10. 通用的将Excel导入数据集的方法

    http://blog.csdn.net/baronyang/article/details/7048563