.NET简谈组件程序设计之(初识.NET线程Thread)

由于多线程的内容比较多我会用几篇文章来讲解。

多线程在我们日常开发过程中用的很多,上一篇“.NET简谈组件程序设计之(异步委托) ”详细的讲解了基于委托的多线程使用,委托是基于后台线程池的原理,这篇文章将主要介绍直接使用Thread对象来实现多线程。

当然使用Thread没有使用Delegate那么容易,毕竟多线程跟异步调用是两个相差很大的技术方向,我也是略懂点皮毛,在此献丑给大家,如有讲的不对的地方还请指出。[王清培版权所有,转载请给出署名]

我们先来理解几个概念,以方便我们学习。

后台线程与前台线程

前台线程:什么叫前台线程,就是我们使用默认的Thread创建出来的没有进行IsBackground属性设置的都是前台线程,因为默认IsBackground是false。前台线程是明确任务的,也就是任何一个前台线程没有结束之前程序是不会自动退出的,除非强制关闭应用程序。

后台线程:后台线程是针对前台线程来说的,将Thread.IsBackground设置为true就是后台线程,后台线程是为前台线程服务的,就是说后台线程没有很强的生命力,只要前台线程都结束了,后台线程都强制结束,哪怕任务还没有完成都不行。所以我们在使用的时候要看情况进行选择。[王清培版权所有,转载请给出署名]

线程的切换

我们来看一段代码,以方便引入主题。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.Remoting;
 using System.Runtime.Remoting.Contexts;
 namespace ConsoleApplication1.多线程和并发管理
 {
	public class MyClass
 	{
     	 	public void ShowMessage()
   	 	{
 			Thread currentthread = Thread.CurrentThread;
 	 		Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
   		}
 	}
 }

 

这是一段很简单的代码,就是一个ShowMessage方法,在方法里面有一个获取当前上下文线程的静态属性Thread.CurrentThread,然后输入该线程的名称和托管ID号;

namespace ConsoleApplication1.多线程和并发管理
 {
 public static class Program
   {
 	static void Main(string[] args)
  	{
 		Thread currentthread = Thread.CurrentThread;
    	 currentthread.Name = "主线程";
    	 Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
        MyClass myclass = new MyClass();
   	ThreadStart start = new ThreadStart(myclass.ShowMessage);
    	Thread thread = new Thread(start);
   	thread.Name = "子线程";
  	thread.Start();
 	Thread.Sleep(1000);//休眠,线程切换
   	Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
     	Console.Read();
   }
 }
 }

 

这是调用代码,我先给主线程起个名字,然后输出。我新建了一个thread线程,这是子线程,调用我们上面定义的方法,用同样的Thread.CurrentThread来获取当前上下文线程,最后让主线程休眠一秒钟。

通过该图我们能清楚的看见,系统在后台自动帮我们进行线程切换,用同一个静态变量就可以获取到当前线程对象。

通过Sleep方法是让当前线程休眠指定的时间断,哪怕当前线程正在CPU上运行着,一旦调用Sleep就立刻放弃CPU给它的时间片,进入阻塞状态。

 [一个线程仅仅是一个进程中的执行路径]

其实线程是执行路径,系统中维护着一个执行路径的命令集合,当我们开启了多个线程的时候其实就是往着个命令集合中存放了很多要执行的命令而已,换句话说命令就是线程队列,用CPU 对它进行时间片的执行。

那么线程是肯定需要一系列的状态的,这个状态时有OS帮我们维持着,因为线程是属于内核层的对象,只有OS才能实时监控着。我们只需要用就行了,有兴趣的朋友可以参考,杰夫瑞 (Jeffrey Richter)《Windows核心编程(第5版)》  一书。

让线程等待而不是切换

Sleep是强制放弃CPU的时间片,然后重新和其他线程一起参与CPU的竞争。用Sleep是会让线程放弃CPU的使用权,而如果我们换成  Thread.SpinWait(100000000),是不会放弃CPU的使用权的,只是让CPU去执行一段没有用的代码,当时间结束之后能立马继续执行,而不是和重新参与CPU的竞争。

在系统资源很丰富的情况下可能这点并不重要,但是在资源缺乏,CPU又不是很好的时候,我想这点还是能改善点性能的。

在此不得不提一个重要的概念,就是线程的调用方和线程主体,线程的调用方就是线程的客户端,是另外一个线程,而不是当前线程主体。

Thread.Join()连接线程

join方法从字面理解是连接的意思,刚接触真的很难理解,什么叫连接。请看一段代码:

Thread currentthread = Thread.CurrentThread;
currentthread.Name = "主线程";
Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
MyClass myclass = new MyClass();
ThreadStart start = new ThreadStart(myclass.ShowMessage);
Thread thread = new Thread(start);
thread.Name = "子线程";
thread.Start();
thread.Join();//阻塞子线程thread线程,直到子线程thread执行结束
Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
Console.Read();

 

通过Join我们可以等待线程结束,连接的意思就是将我和我调用的thread线程连接起来,我要等你结束之后我才能继续执行,这里就是主线程和子线程的关系,只有子线程技术之后,主线程才能继续执行。

Thread.Abort终止线程

利用Abort可以终止一个在执行的线程,但是Abort会在线程上引发一个ThreadAbortException异常。

public void DoWork()
{
     try
   {
      int i = 0;
      while (true)
      {
          Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "|" + i++);
             if (i == 100)
     	     {
 		Console.WriteLine("---------------------------------------------");
                Console.Read();
                break;//退出当前线程执行,尽量不要用Abort结束
              }
        }
   }
  catch (ThreadAbortException err)
        {
          Console.WriteLine(err.Message + "11");
         }
}

 

Thread currentthread = Thread.CurrentThread;
 Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
 MyClass myclass = new MyClass();
ThreadStart start = new ThreadStart(myclass.DoWork);
 Thread thread = new Thread(start);
thread.Start();
Thread.Sleep(5000);
Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId + "是否终止子线程");
 thread.Abort();
Console.Read();

 

Thread.IsBackground = true后台线程

通过设置IsBackground可以让线程处于后台线程,只要前台线程结束,那么后台线程自动终止。

public void DoWork()
   {
  	try
  	{
     	      int i = 0;
              while (true)
              {
    		Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "|" + i++);
            	 //if (i == 100)
             	//{
   		//    Console.WriteLine("---------------------------------------------");
        	 //    Console.Read();
        	 //    break;//退出当前线程执行,尽量不要用Abort结束
         	 //}
    	      }
 	}
  	catch (ThreadAbortException err)
     	 {
          	 Console.WriteLine(err.Message + "11");
      	}

 

 

我们将一段代码注释掉。

Thread currentthread = Thread.CurrentThread;
Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);
MyClass myclass = new MyClass();
ThreadStart start = new ThreadStart(myclass.DoWork);
Thread thread = new Thread(start);
thread.IsBackground = true;
thread.Start();
Thread.Sleep(2000);
Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);

 

 

 

这是调用代码。只要前台线程不结束,后台线程就一直执行。如果我们在最后加上一段Console.ReadLine();代码,那么后台线程会始终运行着。

 

这篇文章就先结束了,下一篇我们将学习关于同步域和上下文的概念。 

 

 

 

时间: 2024-10-06 04:03:50

.NET简谈组件程序设计之(初识.NET线程Thread)的相关文章

.NET简谈组件程序设计之(初识NetRemoting)

在本人的".NET简谈组件程序设计之(初识远程调用)  "一文中,我们了解到什么是远程调用或者说在.NET平台上远程调用是什么样子的,可能和偏低层(Socket\Rpc)的远程调用有点距离.这只是系统为我们封装了假象而已,看不见不代表没有这逻辑,是为我们减轻了劳动负担.[王清培版权所有,转载请给出署名] 这篇文章我们来简单的了解一下在.NET平台上有一个强有力的远程调用武器,也是上一篇文章中我一笔带过的远程英雄.NetRemoting. 其实在.NET平台里面到处都能看见Remotin

.NET简谈组件程序设计之(初识远程调用)

在.NET1.0版本出来的时候,要想进行远程调用基本上都是通过WebService的方式.而随着.NET2.0版本的出现,我们可以通过一个更加方便且高扩展性的框架来进行编写远程调用的程序,也就是我们都比较熟悉的.NetRemoting. 网上对.NetRemoting技术讲解的文章不计其数,但是很少有一本比较全面的.系统的学习书籍.我们都是从哪些零散的知识里慢慢摸索,效果不太理想. 今天我也来简单的介绍一下我理解的Remoting.不仔细研究一下还真不知道它的厉害,完全的托管平台.高扩展性.灵活

.NET简谈组件程序设计之(初识序列化、持久化)

 今天我们来学习在组件开发中经常用到的也是比较重要的技术"序列化". 序列化这个名词对初学者来说不太容易理解,有点抽象.我们还是用传统的分词解释吧,肯定能搞懂它的用意是什么. 解释:数学上,序列是被排成一列的对象(或事件):这样,每个元素不是在其他元素之前,就是在其他元素之后.这里,元素之间的顺序非常重要. 那么我们对照这样的解释来分析一下我们程序中的序列化什么意思.都知道对象的状态是在内存中实时存着的,对象的状态在初始化的时候是通过系统分配的,在后期的程序运行过程中可能对它进行过一些

.NET简谈组件程序设计之(渗入序列化过程)

在本人的上一篇文章".NET简谈组件程序设计之(初识序列化.持久化) "中,我们基本上了解了什么叫序列化和持久化.通过系统为我们提供的服务,我们可以很方便的进行二进制序列化.SOAP协议序列化. 今天这篇文章是来讲解怎么运用一些高级的功能,在序列化.反序列化过程中进行一些控制.[王清培版权所有,转载请给出署名] 这里穿插一句题外话:其实在我们自己编写组件的时候真的有好多东西可以借鉴.NET平台的一些优点,它的功能都不是死的,可以订阅.可以切入,在我们编写组件的时候,我们其实也要好好考虑

.NET简谈组件程序设计之(上下文与同步域)

我们继续学习.NET多线程技术,这篇文章的内容可能有点复杂.在打破常理之后,换一种新的思考模型最为头疼.这篇文章里面会涉及到一些不太常见的概念,比如:上下文.同步域等等.我也是最近才接触这些关于组件编程方面的高深技术,大家一起学习,再大的困难也是有时间限制的,只要我们坚持. 在本人的上一篇文章".NET简谈组件程序设计之(多线程与并发管理一)"中,只是初步的带领我们学习一下关于多线程的一些基本的原理,包括线程切换,线程的开始.执行.等待.结束. 这篇文章的重点是学习关于线程的同步.互斥

.NET简谈组件程序设计之(手动同步)

在上一篇文章".NET简谈组件程序设计之(上下文与同步域)"中,我们学习了关于一些上下文和同步域的概念,可以利用这两个技术来进行自动同步. 今天我们主要学习怎么手动来执行同步,能从更小的粒度进行封锁,以达到最大程度的吞吐量.[王清培版权所有,转载请给出署名] 我们知道线程是进程的运行实体,进程是资源分配单位,而线程是执行单位.照书上所说,线程是程序的执行路径,当我们分配一个线程的时候,要确定线程的执行路径是什么,也就是代码中的ThreadStart委托所指向的入口点方法. 一旦我们手动

.NET简谈组件程序设计之(delegate与event关系)

 本人最近一段时间在学习关于.NET组件编程方面的技术,在学习过程中确实有很多好的东西需要与大家分享.[王清培版权所有,转载请给出署名] 关于什么叫组件编程,其实就是利用.NET来开发基于组件模型的程序,面向组件编程而非面向对象编程,这是一个高度,没有很长时间的学习与磨练 是体会不到这个感觉的.我们现在的开发思想应该是以面向对象为主的,但是如何提升这个高度,只有慢慢的学习了. 其实面向组件编程包含了面向对象编程思想,将一组功能独立的封装起来供以后重复使用,但是在开发组件的过程中需要使用到面向对象

.NET简谈组件程序设计之(详解NetRemoting结构)

在本人的上一篇文章中只是简单的介绍了一下.NETRemoting的一般概念和基本的使用.这篇文章我想通过自己的学习和理解将对.NETRemoting的整体的一个框架进行通俗的讲解,其中最重要的就是信道(管道)处理模型思想,这里面蕴含了很多的设计原理.[王清培版权所有,转载请给出署名].NETRemoting远程处理架构是一个半成品,是.NET给我们的扩展框架,要想用于商业项目必须进行一些安全.性能方面的控制.要想进行一定深度的扩展那就要必须了解它的整体结构,各个点之间的关系才能很好的控制它. 网

.NET简谈组件程序设计之(AppDomain应用程序域)

最近在苦学.NET底层框架模型,发现.NET深入真的不是一般的难,不开源.没有相关系统的官方的书籍做学习资料,只能零散的看MSDN.要想摸熟.NET的模型真的并非易事.慢慢来吧.[王清培版权所有,转载请给出署名] .NET应用程序域(AppDomain)是我们所有.NET应用程序的逻辑宿主容器.初次接触会感觉到AppDomain离我们日常开发比较远,不常用到.其实是我们很少接触一些复杂而底层的系统结构.在日常的开发中,我们多数是基于数据库的管理信息系统(MIS),做增.删.改.查的操作.我始终认