当前位置:  编程技术>.net/c#/asp.net

c#线程Thread示例

    来源: 互联网  发布时间:2014-10-30

    本文导语:  C#是一门支持多线程的语言,因此线程的使用也是比较常见的。由于线程的知识在Win32编程的时候已经说得过多,所以在.Net中很少介绍这部分(可能.Net不觉得这部分是它所特有的)。那么线程相关的问题大致有如下四类(这篇...

C#是一门支持多线程的语言,因此线程的使用也是比较常见的。由于线程的知识在Win32编程的时候已经说得过多,所以在.Net中很少介绍这部分(可能.Net不觉得这部分是它所特有的)。

那么线程相关的问题大致有如下四类(这篇文章只讨论单线程、单线程与UI线程这两方面的问题)。
问题一,线程的基本操作,例如:暂停、继续、停止等;
问题二,如何向线程传递参数或者从中得到其返回值;
问题三,如何使线程所占用的CPU不要老是百分之百;
最后一个,也是问题最多的,就是如何在子线程来控制UI中的控件,换句话说,就是在线程中控制窗体某些控件的显示。

对于问题一,我不建议使用Thread类提供的Suspend、Resume以及Abort这三个方法,前两个有问题,好像在VS05已经屏蔽这两个方法;对于Abort来说,除了资源没有得到及时释放外,有时候会出现异常。如何做呢,通过设置开关变量来完成。

对于问题二,我不建议使用静态成员来完成,仅仅为了线程而破坏类的封装有些得不偿失。那如何做呢,通过创建单独的线程类来完成。

对于问题三来说,造成这个原因是由于线程中进行不间断的循环操作,从而使CPU完全被子线程占有。那么处理此类问题,其实很简单,在适当的位置调用Thread.Sleep(20)来释放所占有CPU资源,不要小看这20毫秒的睡眠,它的作用可是巨大的,可以使其他线程得到CPU资源,从而使你的CPU使用效率降下来。

看完前面的三个问题的解释,对于如何做似乎没有给出一个明确的答案,为了更好地说明如何解决这三个问题,我用一个比较完整的例子展现给大家,代码如下。

代码如下:

//--------------------------- Sub-thread class ---------------------------------------
//------------------------------------------------------------------------------------
//---File:          clsSubThread
//---Description:   The sub-thread template class file
//---Author:        Knight
//------------------------------------------------------------------------------------
//---------------------------{Sub-thread class}---------------------------------------
namespace ThreadTemplate
{
using System;
using System.Threading;
using System.IO;
///
/// Summary description for clsSubThread.
///
public class clsSubThread:IDisposable
{
private Thread thdSubThread = null;
private Mutex mUnique = new Mutex();

private bool blnIsStopped;
private bool blnSuspended;
private bool blnStarted;
private int nStartNum;

public bool IsStopped
{
get{ return blnIsStopped; }
}
public bool IsSuspended
{
get{ return blnSuspended; }
}
public int ReturnValue
{
get{ return nStartNum;}
}

  
public clsSubThread( int StartNum )
{
//
// TODO: Add constructor logic here
//
blnIsStopped = true;
blnSuspended = false;
blnStarted = false;

nStartNum = StartNum;
}

///
/// Start sub-thread
///
public void Start()
{
if( !blnStarted )
{
thdSubThread = new Thread( new ThreadStart( SubThread ) );
blnIsStopped = false;
blnStarted = true;
thdSubThread.Start();
}
}

///
/// Thread entry function
///
private void SubThread()
{
do
{
// Wait for resume-command if got suspend-command here
mUnique.WaitOne();
mUnique.ReleaseMutex();

nStartNum++;

Thread.Sleep(1000); // Release CPU here
}while( blnIsStopped == false );
}

///
/// Suspend sub-thread
///
public void Suspend()
{
if( blnStarted && !blnSuspended )
{
blnSuspended = true;
mUnique.WaitOne();
}
}

///
/// Resume sub-thread
///
public void Resume()
{
if( blnStarted && blnSuspended )
{
blnSuspended = false;
mUnique.ReleaseMutex();
}
}

///
/// Stop sub-thread
///
public void Stop()
{
if( blnStarted )
{
if( blnSuspended )
Resume();

blnStarted = false;
blnIsStopped = true;
thdSubThread.Join();
}
}
#region IDisposable Members
///
/// Class resources dispose here
///
public void Dispose()
{
// TODO:  Add clsSubThread.Dispose implementation
Stop();//Stop thread first
GC.SuppressFinalize( this );
}

#endregion
}
}

那么对于调用呢,就非常简单了,如下:
// Create new sub-thread object with parameters
clsSubThread mySubThread = new clsSubThread( 5 );

mySubThread.Start();//Start thread

Thread.Sleep( 2000 );
mySubThread.Suspend();//Suspend thread

Thread.Sleep( 2000 );
mySubThread.Resume();//Resume thread

Thread.Sleep( 2000 );
mySubThread.Stop();//Stop thread

//Get thread's return value
Debug.WriteLine( mySubThread.ReturnValue );

//Release sub-thread object
mySubThread.Dispose();

在回过头来看看前面所说的三个问题。
对于问题一来说,首先需要局部成员的支持,那么
private Mutex mUnique = new Mutex();

private bool blnIsStopped;
private bool blnSuspended;
private bool blnStarted;

光看成员名称,估计大家都已经猜出其代表的意思。接下来需要修改线程入口函数,要是这些开关变量能发挥作用,那么看看SubThread这个函数。
///
/// Thread entry function
///
private void SubThread()
{
do
{
// Wait for resume-command if got suspend-command here
mUnique.WaitOne();
mUnique.ReleaseMutex();

nStartNum++;

Thread.Sleep(1000);
}while( blnIsStopped == false );
}

函数比较简单,不到十句,可能对于“blnIsStopped == false”这个判断来说,大家还比较好理解,这是一个普通的判断,如果当前Stop开关打开了,就停止循环;否则一直循环。
大家比较迷惑的可能是如下这两句:
mUnique.WaitOne();
mUnique.ReleaseMutex();
这两句的目的是为了使线程在Suspend操作的时候能发挥效果,为了解释这两句,需要结合Suspend和Resume这两个方法,它俩的代码如下。
///
/// Suspend sub-thread
///
public void Suspend()
{
if( blnStarted && !blnSuspended )
{
blnSuspended = true;
mUnique.WaitOne();
}
}

///
/// Resume sub-thread
///
public void Resume()
{
if( blnStarted && blnSuspended )
{
blnSuspended = false;
mUnique.ReleaseMutex();
}
}


为了更好地说明,还需要先简单说说Mutex类型。对于此类型对象,当调用对象的WaitOne之后,如果此时没有其他线程对它使用的时候,就立刻获得信号量,继续执行代码;当再调用ReleaseMutex之前,如果再调用对象的WaitOne方法,就会一直等待,直到获得信号量的调用ReleaseMutex来进行释放。这就好比卫生间的使用,如果没有人使用则可以直接使用,否则只有等待。
明白了这一点后,再来解释这两句所能出现的现象。
代码如下:

mUnique.WaitOne();
mUnique.ReleaseMutex();


当在线程函数中,执行到“mUnique.WaitOne();”这一句的时候,如果此时外界没有发送Suspend消息,也就是信号量没有被占用,那么这一句可以立刻返回。那么为什么要紧接着释放呢,因为不能总占着信号量,立即释放信号量是避免在发送Suspend命令的时候出现等待;如果此时外界已经发送了Suspend消息,也就是说信号量已经被占用,此时“mUnique.WaitOne();”不能立刻返回,需要等到信号量被释放才能继续进行,也就是需要调用Resume的时候,“mUnique.WaitOne();”才能获得信号量进行继续执行。这样才能达到真正意义上的Suspend和Resume。

至于线程的Start和Stop来说,相对比较简单,这里我就不多说了。

现在再来分析一下问题二,其实例子比较明显,是通过构造函数和属性来完成参数和返回值,这一点我也不多说了。如果线程参数比较多的话,可以考虑属性来完成,类似于返回值。

问题三,我就更不用多说了。有人说了,如果子线程中的循环不能睡眠怎么办,因为睡眠的话,有时会造成数据丢失,这方面的可以借鉴前面Suspend的做法,如果更复杂,则牵扯到多线程的同步问题,这部分我会稍后单独写一篇文章。

前三个问题解决了,该说说最常见的问题,如何在子线程中控制窗体控件。这也是写线程方面程序经常遇到的。

首先说说,为什么不能直接在子线程中操纵UI呢。原因在于子线程和UI线程属于不同的上下文,换句比较通俗的话说,就好比两个人在不同的房间里一样,那么要你直接操作另一个房间里的东西,恐怕不行罢,那么对于子线程来说也一样,不能直接操作UI线程中的对象。

那么如何在子线程中操纵UI线程中的对象呢,.Net提供了Invoke和BeginInvoke这两种方法。简单地说,就是子线程发消息让UI线程来完成相应的操作。

这两个方法有什么区别,这在我以前的文章已经说过了,Invoke需要等到所调函数的返回,而BeginInvoke则不需要。

用这两个方法需要注意的,有如下三点:
第一个是由于Invoke和BeginInvoke属于Control类型的成员方法,因此调用的时候,需要得到Control类型的对象才能触发,也就是说你要触发窗体做什么操作或者窗体上某个控件做什么操作,需要把窗体对象或者控件对象传递到线程中。

第二个,对于Invoke和BeginInvoke接受的参数属于一个delegate类型,我在以前的文章中使用的是MethodInvoker,这是.Net自带的一个delegate类型,而并不意味着在使用Invoke或者BeginInvoke的时候只能用它。参看我给的第二篇文章(《如何弹出一个模式窗口来显示进度条》),会有很多不同的delegate定义。

最后一个,使用Invoke和BeginInvoke有个需要注意的,就是当子线程在Form_Load开启的时候,会遇到异常,这是因为触发Invoke的对象还没有完全初始化完毕。处理此类问题,在开启线程之前显式的调用“this.Show();”,来使窗体显示在线程开启之前。如果此时只是开启线程来初始化显示数据,那我建议你不要使用子线程,用Splash窗体的效果可能更好。
线程的四个相关问题已经说完了,这篇文章只说了单线程,以及单线程与UI线程交互的问题。其中涉及到的方法不一定是唯一的,因为.Net还提供了其他类来扶助线程操作,这里就不一一罗列。

    
 
 

您可能感兴趣的文章:

  • c#多线程更新窗口(winform)GUI的数据
  • c# winform 关闭窗体时同时结束线程实现思路
  • c#多线程读取注册表 c#多线程的小例子
  • C#实现终止正在执行的线程
  • c#后台线程访问前台控件并显示信息示例
  • C#线程间不能调用剪切板的解决方法
  • C#实现线程池的简单示例
  • c# 多线程操作progressBar进度条控件的例子
  • C#子线程更新UI控件的方法实例总结
  • C#实现窗体与子线程的交互的方法
  • C#通过接口与线程通信(捕获线程状态)示例代码
  • C#利用子线程刷新主线程分享教程
  • 描述C#多线程中lock关键字的使用分析
  • C#中的多线程多参数传递详解
  • C# 多线程更新进度条progressBar控件的代码一例
  • C# 多线程复制文件并显示进度条的代码
  • c#(asp.net)线程配置总结
  • c#线程同步的问题与实例分析
  • c#多线程中Lock()关键字的用法小结
  • c#钩子本线程内消息拦截的方法
  • c#线程间传递参数详解
  • java多线程编程之捕获子线程异常示例
  • 输出java进程的jstack信息示例分享 通过线程堆栈信息分析java线程
  • python创建线程示例
  • python线程锁(thread)学习示例
  • android使用handler ui线程和子线程通讯更新ui示例
  • c语言多线程编程使用示例
  • java通过共享变量结束run停止线程的方法示例
  • java线程并发semaphore类示例
  • java信号量控制线程打印顺序的示例分享
  • java线程并发countdownlatch类使用示例
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Java中多线程相关类Thread介绍
  • Java多线程单元测试 Thread Weaver
  • c++的boost库多线程(Thread)编程(线程操作,互斥体mutex,条件变量)详解
  • 用kthread_run创建kernel thread, 能不能限制线程的数目?
  • Linux/Unix/POSIX thread 如何等待线程的结束,并且可指定超时?
  • java Thread 多线程
  • Android开发笔记之:如何安全中止一个自定义线程Thread的方法
  • java中thread线程start和run的区别
  • 在内核模块中通过kernel_thread创建的线程,用kill_proc结束会死机呢?
  • linux下main thread如何使用pthread_join等待子线程结束后再退出
  • JAVA多线程Thread和Runnable的实现
  • 深入多线程之:解析线程的交会(Thread Rendezvous)详解
  • Python中多线程thread与threading的实现方法
  • 如果有三个线程在Waiting(Ready to Run)状态,其优先级分别为5,6,7,当Thread scheduler调度时,那个先运行?
  • java多线程编程之使用thread类创建线程
  • java线程之用Thread类创建线程的方法
  • java基本教程之Thread中start()和run()的区别 java多线程教程
  • 用pthread_kill(thread_id,0);判断线程是否存在 竟然产生core,为什么?
  • 多线程传递Context multi-thread context(MTC)
  • Windows和Linux下C++类成员方法作为线程函数方法介绍
  • 一个进程创建了两个线程,如何使得当任何一个线程(比如线程a)结束时,同时也结束线程b,也就是使两个线程一起死掉,怎么办呢?
  • Linux下GCC内置原子操作函数(多线程资源访问)介绍
  • java 线程,对当前线程(非主线程)调用sleep,为什么主线程(窗口)也没反应了
  • 如何实现一个线程组内多线程的非同不执行,即一个线程执行完毕后再执行下一个线程???
  • 请问:进程创建的线程是怎样运行的啊,线程的处理函数运行完了,线程就退出了吗?
  • 关于线程的问题,什么样的线程不是active线程?
  • 请问Linux核心支持多线程吗?开发库有线程库吗?线程好用吗?(稳定?)
  • 请问,在一个进程中创建多线程时如何能避免不同的线程获得同一个线程标识
  • 我的一个多线程服务里, 总是有一个线程莫名其妙的变成僵尸线程。
  • 能否通过线程id控制线程的状态?或是观察到线程的状态?
  • 如何在一个线程中启动另外一个线程,然后本线程就退出?


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3