c#winform多线程开发

上传人:公**** 文档编号:431218154 上传时间:2022-12-12 格式:DOC 页数:4 大小:47.50KB
返回 下载 相关 举报
c#winform多线程开发_第1页
第1页 / 共4页
c#winform多线程开发_第2页
第2页 / 共4页
c#winform多线程开发_第3页
第3页 / 共4页
c#winform多线程开发_第4页
第4页 / 共4页
亲,该文档总共4页,全部预览完了,如果喜欢就下载吧!
资源描述

《c#winform多线程开发》由会员分享,可在线阅读,更多相关《c#winform多线程开发(4页珍藏版)》请在金锄头文库上搜索。

1、一 Thread 类库Windows 是一个多任务的系统,如果你使用的是windows 2000及其以上版本,你可以通过任务管理器查看当前系统运行的程序和进程。什么是进程呢?当一个程序开始运行时,它就是一个进程, 进程所指包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的,线程是程序中的一个执行流,每个线程都有自己的专有寄存器( 栈指针、程序计数器等) ,但代码区是共享的,即不同的线程可以执行同样的函数。多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。一 关于 T

2、hread 的说明在 framework class library 中,所有与多线程机制应用相关的类都是放在命名空间中的。其中提供 Thread 类用于创建线程, ThreadPool 类用于管理线程池等等,此外还提供解决了线程执行安排, 死锁,线程间通讯等实际问题的机制。 如果你想在你的应用程序中使用多线程,就必须包含这个类。 Thread 类有几个至关重要的方法,描述如下:Start():启动线程Sleep(int):静态方法,暂停当前线程指定的毫秒数Abort():通常使用该方法来终止一个线程Suspend() :该方法并不终止未完成的线程,它仅仅挂起线程,以后还可恢复。Resume(

3、) :恢复被Suspend() 方法挂起的线程的执行线程入口使程序知道该让这个线程干什么事,在(delegate )来提供的, 你可以把 ThreadStart数,当调用()方法后,线程就开始执行C#中,线程入口是通过ThreadStart代理理解为一个函数指针,指向线程要执行的函ThreadStart所代表或者说指向的函数。ThreadState在各种情况下的可能取值如下:Aborted :线程已停止AbortRequested :线程的 () 方法已被调用,但是线程还未停止Background :线程在后台执行,与属性有关Running :线程正在正常运行Stopped :线程已经被停止S

4、topRequested :线程正在被要求停止Suspended:线程已经被挂起(此状态下,可以通过调用Resume()方法重新运行)SuspendRequested :线程正在要求被挂起,但是未来得及响应Unstarted :未调用 () 开始线程的运行WaitSleepJoin:线程因为调用了Wait(),Sleep()或 Join()等方法处于封锁状态二 Winform 中使用的 thread首先可以看看最直接的方法, 也是 下支持的方法。 但请注意的是, 此方法在 以后就已经是一种错误的方法了。csharp view plain copy在 CODE上查看代码片派生到我的代码片publ

5、ic partial class Form1 : Formpublic Form1()InitializeComponent();private void Form1_Load(object sender, EventArgs e)Thread thread = new Thread(ThreadFuntion);= true;();private void ThreadFuntion()while (true)=(1000);这段 code 在 vs2005 或者 2008 上都抛出异常:Cross-threadoperationnot valid:ControltextBox1 acces

6、sed from a thread other than the thread it was created on .这是因为以后加强了安全机制,不允许在winform 中直接跨线程访问控件的属性。那么怎么解决这个问题呢,下面提供几种方案。第一种方案: 在 Thread 创建之气, 将 设为 false 。 此代码告诉编译器:在这个类中我们不检查跨线程的调用是否合法 (如果没有加这句话运行也没有异常, 那么说明系统以及默认的采用了不检查的方式)。然而,这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个 static 的,也就

7、是说无论我们在项目的什么地方修改了这个值, 他就会在全局起作用。 而且像这种跨线程访问是否存在异常, 我们通常都会去检查。 如果项目中其他人修改了这个属性, 那么我们的方案就失败了,我们要采取另外的方案。第二种方案csharp view plain copy在 CODE上查看代码片派生到我的代码片namespace TestInvokerpublic partial class Form1 : Formpublic Form1()InitializeComponent();private void button1_Click(object sender, EventArgs e)Threadt

8、hread=newThread(newThreadStart(StartSomeWorkFromUIThread);= true;();et框架上似乎没有发现问题,但是这根本就是错的,更糟糕的是,程序员在这里不会得到任何错误提示,一开始就上当受骗,之后会莫明其妙地发现其他错误,这就是 Windows Form 多线程编程的痛苦所在。笔者试过花很多时间来Debug 自己写的Splash窗口突然消失的问题,结果还是失败了:笔者在软件的引导过程中,用另外一个线程里创建了一个Splash窗口来显示欢迎信息,然后尝试把主线程里引导的状态直接写入到Splash窗口上的控件中,开始还OK,可是过一会Spla

9、sh 窗口就莫明其妙消失了。理解了这一点,我们应该留意到,有时候即使没有用来显式创建一个线程,我们也可能因为使用了异步委托的 BeginInvoke 方法来隐式创建了线程 ( 从线程池里 ) ,在这种线程里也同样不能调用 UI 线程所创建的控件的成员。第四,由于上述限制,我们可能会感到很不方便,的确,当我们利用一个新创建的线程来执行某些花时间的运算时,怎样知道运算进度如何并通过UI 反映给用户呢?解决方法很多! 比如熟悉多线程编程的用户很快会想到,我们采用一些低级的同步方法,工作者线程把状态保存到一个同步对象中,让 UI 线程轮询 (Polling) 该对象并反馈给用户就可以了。不过,这还是挺

10、麻烦的,实际上不用这样做,Control类 ( 及其派生类 ) 对象有一个 Invoke方法很特别, 这是少数几个不受线程限制的成员之一。我们前面说到, 绝对不要在任何其他线程里面调用非本线程创建的控件的成员时,也说了“只有极个别情况例外”,这个 Invoke方法就是极个别情况之一-Invoke方法可以从任何线程里面调用。下面我们来讲解Invoke 方法。Invoke 方法的参数很简单,一个委托,一个参数表( 可选 ) ,而 Invoke 方法的主要功能就是帮助你在UI 线程 ( 即创建控件的线程) 上调用委托所指定的方法。Invoke方法首先检查发出调用的线程( 即当前线程 ) 是不是 UI

11、 线程,如果是,直接执行委托指向的方法,如果不是,它将切换到UI 线程,然后执行委托指向的方法。不管当前线程是不是UI 线程, Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的线程( 如果需要的话 ) ,返回。注意,使用 Invoke 方法时, UI 线程不能处于阻塞状态。以下MSDN里关于 Invoke 方法的说明:plain view plain copy在 CODE上查看代码片派生到我的代码片“控件上有四种方法可以安全地从任何线程进行调用:InvokeEndInvoke和 CreateGraphics。对于所有其他方法调用,则应使用调用、 BeginInvoke、(in

12、voke)方法之一封送对控件的线程的调用。委托可以是EventHandler的实例,在此情况下,发送方参数将包含此控件,而事件参数将包含。委托还可以是MethodInvoker的实例或采用void参数列表的其他任何委托。调用EventHandler或 MethodInvoker委托比调用其他类型的委托速度更快。”好了,说完 Invoke ,顺便说说BeginInvoke ,毫无疑问这是Invoke 的异步版本 (Invoke是同步完成的 ) ,不过大家不要和上面的委托中的BeginInvoke混淆,两者都是利用不同线程来完成工作,但是控件的BeginInvoke方法总是使用UI 线程,而其他的

13、异步委托调用方法则是利用线程池里的线程。相对 Invoke 而言,使用 BeginInvoke 稍稍麻烦一点,但还是那句话,异步比同步效果好,尽管复杂些。比如同步方法可能出现这样一种死锁情况: 工作者线程通过 Invoke 同步调用 UI 线程里的方法时会阻塞,而万一 UI 线程正在等待工作者线程做某件事时怎么办?因此,能够使用异步方法时应尽量使用异步方法。下面我们利用所学到的知识来改写上面那个简单的例子:csharp view plain copy在 CODE上查看代码片派生到我的代码片/ 这是由 UI 线程定义的 Label 控件private Label lblStatus;/ 以下方法不在 UI 线程上执行private void RunsOnWorkerThread() DoSomethingSlow();/ Do UI update on UI thread object pList = this, ;(new (UpdateUI), pList);/ 切换回 UI 线程执行的入口private void UpdateUI(object o, e) / 现在没问题了,使用 Invoke 使得线程总是回到 UI 线程,所以我们可以放心大胆地调用控件的成员了= Finished!;第五,关于多线程编程还要考虑线程之间的同步问题、死锁和

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 国内外标准规范

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号