| 网站首页 | 业界新闻 | 技术文章 | 视频教程 | 下载频道 | 程序源码 | 个人空间 | 编程论坛 |
 
| 技术教程首页 | 开发语言 | WEB开发 | .NET技术 | 数据库 | 操作系统 | 网页制作 |
 
 
您现在的位置: 编程中国 >> 技术教程 >> .NET技术 >> VC.NET >> VC.NET技术资料 >> 正文
  ►  .NET 框架与多线程
.NET 框架与多线程
作者:袁剑    阅读人次:……    文章来源:MSDN    发布时间:2007-9-5    网友评论()条
 
 
线程概述
 
  线程是CPU时间片分配的单位,不同的线程可以具有不同的优先级,每个进程至少会有一个主线程。在.NET框架中最基本的执行单元是线程,托管代码是以单线程开始执行的,但在执行期间可以产生附加的线程来帮助完成指定的任务。线程分为前台线程(所有前台线程都必须退出之后,当前进程才能退出)和后台线程(进程随时可以退出,不等待后台线程退出)。
  对于耗时非常长而又不想堵塞界面的操作、服务器端的应用、同时支持多用户并发的环境或者发挥多处理器的作用的时候都应该考虑使用多线程,但是使用线程需要非常谨慎地分析同步情况和线程调度本身的开销。
 
线程控制
 
  线程控制包括线程启动、挂起、恢复、休眠、终止等,在下面的这个列子里将会对线程控制做一个大体描述。
 

public class MyThread

{

            public static void Work()

            {

                        try

                        {

                                    for( int i = 0; i < 4; i++ )

                                    {

                                                Console.WriteLine( Thread.CurrentThread.Name + "正在计算" + i.ToString() );

                                                Thread.Sleep( 50 );

                                    }

                        }

                        catch( ThreadAbortException e )

                        {

                                    Console.WriteLine( "错误信息:{0}", e.Message );

                                    Thread.ResetAbort();//取消主线程要求中止的请求,如不执行则ThreadAbortException会在catch块末端再次引发

                        }

                        Console.WriteLine( Thread.CurrentThread.Name + "完成工作!" );

            }

}

 

class ThreadAbortTest

{

            public static void Main()

            {

                        Console.WriteLine( "主线程启动!");

                        Thread thread = new Thread( new ThreadStart( MyThread.Work ) );//MyThread.Work代表要执行的线程函数,它可以是静态的,也可以是某个类实例的方法,它是要执行的线程函数的委托

                        thread.Name = "MyThread";

                        thread.Start();//线程启动后将被CPU调度,但不一定是马上执行,所以同样的例子在不同的机器上可能会有不同的结果。

                        Console.WriteLine( "主线程第一次休眠!");

                        Thread.Sleep( 100 );

                        Console.WriteLine( "MyThread被挂起!");

                        thread.Suspend();//挂起子线程

                        Console.WriteLine( "主线程第二次休眠!");

                        Thread.Sleep( 100 );

                        Console.WriteLine( "MyThread被恢复!");

                        thread.Resume();//恢复子线程

                        thread.Abort();//终止子线程

                        thread.Join();//直到到子线程完全终止了,主线程才继续运行

                        Console.WriteLine( "主线程终止!" );

                        Console.ReadLine();

            }

}

 
  程序启动后会创建一个名为MyThread的辅助线程并通过调用thread.Start启动它,然后调用Thread.Sleep( 100 )休眠100微妙,这时辅助线程一直在运行,接下来主线程调用thread.Suspend挂起辅助线程并再休眠100微妙后再调用Thread.Sleep恢复辅助线程,在被挂起和被恢复这段时间内辅助线程被阻塞,紧跟着主线程执行thread.Abort方法终止辅助线程并执行thread.Join等待辅助线程结束,在辅助线程接收到终止请求时它已经工作并又执行了一次循环,辅助线程捕捉到主线程要求终止的异常,执行Thread.ResetAbort退出循环以便执行清理工作。从上面的例子可以清晰的看出控制并发线程整个的过程。运行结果如下图2所示:
 
 
线程同步
 
  启动线程很容易,但是让他们协调工作却很难,设计一个多线程的程序时最难的就是计算出并发的线程会在哪里冲突并用同步逻辑来阻止冲突的发生。
.NET框架提供了下面的几个线程同步类:
 AutoResetEvent:阻塞线程直到另一个线程设置事件
 Interlocked:以线程安全的方式进行简单操作、如递增或递减整数
 ManualResetEvent:阻塞一个或多个线程直到另一个线程设置事件
 Monitor:防止一个以上的线程同时访问一个资源
 Mutex:防止一个或多个以上的线程同时访问一个资源,并能跨越应用程序或进程的边界
 ReaderWriterLock:使多个线程可以同时读取一个资源,但不允许重叠的读写或写操作
在以上几个类里面我们用得最多是Monitor,下面将重点对Monitor类进行讲解:
Monitor的几个重要的方法:
 Enter:在访问资源前调用并在该资源上声明一个锁以判断是否该资源被其他资源所占用,如果是则该线程被阻塞直到可以获得该资源为止。
 Exit:在访问完该资源后调用以释放对资源的锁便于其他线程访问。
 Wait:暂时放弃调用线程对该资源的锁。
 Pluse:通知在Wait中阻塞的线程,使得下一个等待线程在当前线程释放锁后可以运行。
  在C#里有lock关键字以取代Monitor的Enter和Exit,在功能上
 
lock ( SomeResource )
{
	//您的处理代码
}
等价于:
Monitor.Enter( SomeResource );
try
{
	//您的处理代码
}
finally
{
	Monitor.Exit( );
}
 
  下面的例子向您具体演示一下怎样用Monitor实现生产者-消费者的问题。表面上看来每个时刻只有一个方法可以执行,但是它们却是并发执行的。首先是Producer得到了锁,他通过调用Monitor.Wait阻塞自身,这时Consumer得到了锁,Consumer调用Monitor.Pulse使得Producer处于准备执行状态,然后Consumer调用Monitor.Wait阻塞自身,这时Producer从Wait调用中醒来,生成一个资源放入队列中,调用Monitor.Pulse使得Consumer从Wait调用中醒来,Consumer从队列中取得资源,接下来Consumer通过调用Monitor.Pulse和Monitor.Wait使得整个进程继续下去。
 

class MonitorSample

{

            private Queue _queue = new Queue();

            public void Producer()

            {

                        int counter = 0;

                        lock( _queue )//判断该资源是否被其他线程占用

                        {

                                    while( counter < 2 )

                                    {

                                                Monitor.Wait( _queue );//暂时放弃调用线程对该资源的锁,让Consumer执行

                                                _queue.Enqueue( counter );//生成一个资源

                                                Console.WriteLine( String.Format( "生产:{0}", counter ) );

                                                Monitor.Pulse( _queue );//通知在Wait中阻塞的Consumer线程即将执行

                                                counter++;

                                    }

                        }

            }

            public void Consumer()

            {

                        lock( _queue )

                        {

                                    Monitor.Pulse( _queue );//通知在Wait中阻塞的Producer线程即将执行

                                    while( Monitor.Wait( _queue, 10 ) )

                                    {

                                                int counter = ( int ) _queue.Dequeue();//取出一个资源

                                                Console.WriteLine( String.Format( "消费:{0}", counter ) );

                                                Monitor.Pulse( _queue );//通知在Wait中阻塞的Producer线程即将执行

                                    }

                        }

            }

            static void Main(string[] args)

            {

                        MonitorSample monitor = new MonitorSample();           

                        Thread producer = new Thread( new ThreadStart( monitor.Producer ) );

                        Thread consumer = new Thread( new ThreadStart( monitor.Consumer ) );

                        producer.Start();

                        consumer.Start();

                        producer.Join();

                        consumer.Join();           

                        Console.ReadLine();

            }

}

 
 
小结
 
  本文仅仅只是展示了.NET框架强大功能的冰山一角,通过两个实例具体讲解了在.NET框架下开发多线程程序的必备知识,当您熟悉以后应该也会认为编写多线程程序是.NET框架里最有趣和有用的东西。
 
参考资源
Microsoft Developer Network http://msdn.microsoft.com
Microsoft .NET 程序设计技术内幕 Jeff Prosise,王铁等译,清华大学出版社
袁剑
Microsoft ASP.NET MVP
http://blog.joycode.com/gOODiDEA

上一页  [1] [2] 

 

 
文章录入:编辑01    责任编辑:编辑01 
  • 上一篇文章:

  • 下一篇文章:

  •  
    相关文章
    Java多线程技术中所有方法的详细解
    .NET企业级应用架构设计系列之技术
    在.NET与Java间进行Web Service交互
    Java与.NET 谁才能主宰未来?
    多线程、Socket技术及委托技术的关
    Visual C#多线程参数传递浅析
    自动化基础概念之“COM组件与接口”
    .Net下进程外COM服务器的实现
    四种进程或线程同步互斥的控制方法
    如何在.NET中实现脚本引擎 (CodeDo
    原创地带
    24小时热门帖子