c#.net多线程编程教学(2):Thread类

发布时间:2020-03-13 20:47    浏览次数 :

[返回]

第一个C#程序:经典例程Hello World

这章将向大家介绍.NET中的线程API,怎么样用C#创建线程,启动和停止线程,设置优先级和状态.

  • “Hello World”可以说是学习每一种编程语言的第一个例程了。我们可以在NotePad、Wordpad等任何编辑器中输入以下的C#代码,并保存为helloworld.cs,最后在命令行中执行csc helloworld.cs来运行文件:

  • // using system

  • using System;

  • class Hello

  • {

  • static void Main() { // display output on console

  • Console.WriteLine("Hello,C# World!");

  • }

  • }

  • 用OpenFileDialog类浏览或打开文件

  • 同VC++中CfileDialog的 Open 方法相同,C#中的OpenFileDialog类可用于打开一个文件。这个类是从FileDialog派生出来的。用这个类中的 OpenFile方法打开一个文件,然后就可以通过流(steam)来读取这个文件。

  • 请看下面的例程代码,它使用 OpenFileDialog类浏览一个文件:

  • OpenFileDialog fdlg = new OpenFileDialog();

  • fdlg.Title = "C# Corner Open File Dialog" ;

  • fdlg.InitialDirectory = @"c:" ;

  • fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*" ;

  • fdlg.FilterIndex = 2 ;

  • fdlg.RestoreDirectory = true ;

  • if(fdlg.ShowDialog() == DialogResult.OK)

  • {

  • textBox1.Text = fdlg.FileName ;

  • }

  • Title一行设置打开对话框的标题,Filter一行为打开的文件类型设置一个过滤器,FileName一行包含了所选中的文件名。

  • 下图就是运行的结果:

  • 从C#中调用COM组件

  • .NET框架是COM的一个自然发展,两者共享许多核心要素,这包括组件的再利用以及语言的中立性。为了向后兼容,COM Interop可以使用现存的COM组件而不要求对原始组件进行修改。当一个 .NET 框架开发人员想将COM代码合并到一个管理应用程序中时,就可以用COM Interop功能引入相关的COM类型。引入之后,这个COM类型就可以使用了。这属于前期连接。但是有时候你需要对象的后期连接,这在.NET中也能实现,使用名称空间映射就可以通过后期连接来调用COM对象。

  • 这里介绍一个应用程序例程,它将调用Excel,并且通过使用后期连接使它可视。

  • 后期连接将使用Reflectionb的Type类,这个Type类有许多方法可以取得COM对象,就象我们已经使用过的 GetTypeFromProgID("Application"),这个方法从系统注册表中得到COM ID,然后使用STATIC类的成员 Activator.CreateInstance()创建这个COM对象的一个新例示。

  • 要想调用COM对象的方法、函数和属性,就必须使用包含正确设置的Type对象的InvokeMethod()方法。这个方法接受一些参数变量,其中最重要的一个是方法类型的ex属性(get或set)。在例子中我们为Excel.Visible使用了set属性,从而使Excel应用程序可视。

  • 我们将尝试在.NET环境中调用Excel应用程序。这是一个后期连接应用程序,因为如果是前期连接的话你就需要使用COM对象的RCW(RunTime Callable Wraper:运行时间的可调用包)来完成下面的命令行程序tblimp所完成的任务:

  • ex. c:> tblimp /out:

  • 下载COMinDOTNET.zip,这是一个控制台应用程序。下面是调用excel的代码:

  • //Variable

  • Type excel;

  • object[] parameter= new object[1];

  • object excelObject;

  • try

  • {

  • //Get the excel object

  • excel = Type.GetTypeFromProgID("Excel.Application");

  • //Create instance of excel

  • excelObject = Activator.CreateInstance(excel);

  • //Set the parameter whic u want to set

  • parameter[0] = true;

  • //Set the Visible property

  • excel.InvokeMember("Visible", BindingFlags.SetProperty, null, excelObject, parameter);

  • }

  • catch(Exception e)

  • {

  • Console.WriteLine("Error Stack {0} ", e.Message) ;

  • }

  • finally

  • {

  • //When this object is destroyed the Excel application will be closed

  • //So Sleep for sometime and see the excel application

  • Thread.Sleep(5000);

  • //Relaese the object

  • //GC.RunFinalizers()

  • }

  • 创建多线程应用程序

  • 在.NET和C#中编写一个多线程应用程序将非常得容易。即使对于那些从没有用C#编写过多线程应用程序的初学者,只需遵循以下这些简单的步骤就可以实现目的。

  • 定义名称空间

  • 在.NET中,多线程功能是在System.Threading名称空间中定义的。因此,在使用任何线程类之前,必须定义 System.Threading名称空间。定义方法如下:

  • using System.Threading;

  • 启动线程

  • System.threading名称空间中的Thread类代表一个线程对象,用这个类对象可以创建新的线程,删除、暂停和恢复线程。 下面的代码使用Thread类创建一个新的线程,然后启动这个线程:

  • thread = new Thread(new ThreadStart( WriteData ));

  • thread.Start();

  • 其中WriteData是这个线程要执行的一个函数,代码如下:

  • protected void WriteData()

  • {

  • string str ;

  • for ( int i = 0; i<=10000; i++ )

  • {

  • str = "Secondary Thread" + i.ToString();

  • Console.WriteLine(listView1.ListItems.Count, str, 0, new string[]{""} );

  • Update();

  • }

  • }

  • 杀死线程

  • Thread类的Abort方法用于永久地杀死一个线程。但是请注意,在调用Abort方法前一定要判断线程是否还激活,也就是判断thread.IsAlive的值:

  • if ( thread.IsAlive )

  • {

  • thread.Abort();

  • }

  • 暂停线程

  • Thread.Sleep方法用于将一个线程暂停一段时间,代码如下:

  • thread.Sleep();

  • 设置线程的优先权

  • 我们可以使用Thread类的ThreadPriority属性设置线程的优先权。线程优先权的取值范围是Normal、AboveNormal、BelowNormal、Highest或者Lowest。请看下面的设置代码:

  • thread.Priority = ThreadPriority.Highest;

  • 延迟线程

  • Thread类的Suspend方法可以延迟一个线程。线程被延迟到调用Resume方法为止。

  • if (thread.ThreadState = ThreadState.Running )

  • {

  • thread.Suspend();

  • }

  • 恢复被延迟的线程

  • 调用Resume方法可以恢复一个被延迟的线程。如果线程没有被延迟,Resume方法就是无效的。

  • if (thread.ThreadState = ThreadState.Suspended )

  • {

  • thread.Resume();

  • }

  在.NET中编写的程序将被自动的分配一个线程.让我们来看看用C#编程语言创建线程并且继续学习线程的知识。我们都知道.NET的运行时环境的主线程由Main ()方法来启动应用程序,而且.NET的编译语言有自动的垃圾收集功能,这个垃圾收集发生在另外一个线程里面,所有的这些都是后台发生的,让我们无法感觉到发生了什么事情.在这里默认的是只有一个线程来完成所有的程序任务,但是正如我们在第一篇文章讨论过的一样,有可能我们根据需要自己添加更多的线程让程序更好的协调工作。比如说我们的例子中,一个有用户输入的同时需要绘制图形或者完成大量的运算的程序,我们必须得增加一个线程,让用户的输入能够得到及时的响应,因为输入对时间和响应的要求是紧迫的,而另外一个线程负责图形绘制或者大量的运算。

  .NET 基础类库的System.Threading命名空间提供了大量的类和接口支持多线程。这个命名空间有很多的类,我们将在这里着重讨论Thread这个类。

  System.Threading.Thread类是创建并控制线程,设置其优先级并获取其状态最为常用的类。他有很多的方法,在这里我们将就比较常用和重要的方法做一下介绍:

  Thread.Start():启动线程的执行;

  Thread.Suspend():挂起线程,或者如果线程已挂起,则不起作用;

  Thread.Resume():继续已挂起的线程;

  Thread.Interrupt():中止处于 Wait或者Sleep或者Join 线程状态的线程;

  Thread.Join():阻塞调用线程,直到某个线程终止时为止

  Thread.Sleep():将当前线程阻塞指定的毫秒数;

  Thread.Abort():以开始终止此线程的过程。如果线程已经在终止,则不能通过Thread.Start()来启动线程。

  通过调用Thread.Sleep,Thread.Suspend或者Thread.Join可以暂停/阻塞线程。调用Sleep()和Suspend()方法意味着线程将不再得到CPU时间。这两种暂停线程的方法是有区别的,Sleep()使得线程立即停止执行,但是在调用Suspend()方法之前,公共语言运行时必须到达一个安全点。一个线程不能对另外一个线程调用Sleep()方法,但是可以调用Suspend()方法使得另外一个线程暂停执行。对已经挂起的线程调用Thread.Resume()方法会使其继续执行。不管使用多少次Suspend()方法来阻塞一个线程,只需一次调用Resume()方法就可以使得线程继续执行。已经终止的和还没有开始执行的线程都不能使用挂起。Thread.Sleep(int x)使线程阻塞x毫秒。只有当该线程是被其他的线程通过调用Thread.Interrupt()或者Thread.Abort()方法,才能被唤醒。

  如果对处于阻塞状态的线程调用Thread.Interrupt()方法将使线程状态改变,但是会抛出ThreadInterupptedException异常,你可以捕获这个异常并且做出处理,也可以忽略这个异常而让运行时终止线程。在一定的等待时间之内,Thread.Interrupt()和Thread.Abort()都可以立即唤醒一个线程。

  下面我们将说明如何从一个线程中止另外一个线程。在这种情况下,我们可以通过使用Thread.Abort()方法来永久销毁一个线程,而且将抛出ThreadAbortException异常。使终结的线程可以捕获到异常但是很难控制恢复,仅有的办法是调用Thread.ResetAbort()来取消刚才的调用,而且只有当这个异常是由于被调用线程引起的异常。因此,A线程可以正确的使用Thread.Abort()方法作用于B线程,但是B线程却不能调用Thread.ResetAbort()来取消Thread.Abort()操作。

上一篇:委托解释
下一篇:没有了