C#.NET线程与文件操作

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、多线程技术
<一> 线程概述
使用C#编写任何程序时,都有一个入口:Main()方法。

程序从Main()方法的第一条语句开始执行,直到这个方法返回为止。

这样的程序结构非常适合于一个可识别的任务序列的程序,但程序常常需要同时完成多个任务。

例如在使用文字处理软件的时候,用户在输入文字的同时,软件能同步进行拼写检查而不需要用记的等待;再如在一个应用程序的打印功能中,如果程序只能执行一个任务序列,用户可能需要等待所有的打印任务完成后才能继续操作,这时就需要能让程序同时处理多个任务的能力。

在上面的示例中提到的拼写检查和打印功能说明了应用程序需要处理多个任务的情形,所以最明显的解决方案是给应用程序提供多个执行线程。

线程表示计算机执行的指令序列,从Windows 95操作系统开始引入了多线程机制,应用程序可以同时执行多个任务序列。

每次创建一个新执行线程时,都需要指定从哪个方法开始执行。

在C#应用程序中,第一个线程总是Main()方法,因为第一个线程是由.NET运行库开始执行的,Main()方法是.NET运行库选择的第一个方法。

后续的线程由应用程序在内部启动,即应用程序可以创建和启动新的线程。

1、多线程工作方式
一个处理器在某一刻只能处理一个任务,对于一个多处理器系统,理论上它可以同时执行多个指令——每个处理器执行一个指令,但大多数人使用的是单处理器计算机,同时执行多个指令的情况是不可能发生的。

表面上Windwos操作系统上可以同时处理多个任务,这个过程称为抢先式多任务处理,所谓抢先式多任务处理,是指Windwos在某个进程中选择一个线程,该线程运行一小段时间。

这个时间非常短,不会超过几毫秒。

这段很短的时候称为线程的时间片。

过了这个时间片后,Windows就收回控制权,选择下一个被分配了时间片的线程。

这些时间非常短,我们可以认为许多事件是同时发生的。

即使应用程序只有一个线程,抢先式多任务处理的进行也在进行,因为系统上运行了许多其他进程,每个进程都需要一定的时间片来完成其线程。

当屏幕上有许多应用程序窗口时,每个窗口都代表不同的进程,可以单击它们中的任一个,让它显示响应。

这种响应不是即时的,在相关进程中下一个负责处理该窗口的用户输入的线程得到一个时间片时,这种响应才会发生。

如果系统非常忙,就需要等待,但这种等待的时间非常短暂,用户不会察觉到。

2、什么时候使用多线程
应用多线程技术最大的误区在于没有分清适用的情况就盲目地使用多线程。

除非运行一个多处理器计算机,否则在CPU密集的任务中使用两个线程不能节省多少时间,理解这一点是很重要的。

在单处理器计算机上,让两个线程式同时进行100万次运算所花的时间与让一个线程进行200万次运算是相同的,甚至使用两个线程式所用的时间会略长,因为要处理另一个线程,操作系统必须用一定的时间切换线程,但这种区别可以忽略不计。

使用线程带来的负面因素是必须额外考虑线程的并发、同步等线程安全问题,从而使得程序更加复杂而难以维护。

有些场合则使用多线程技术非常适合,如一个服务器进程需要并发处理来自不同客户端的访问。

此外,使用多个线程的优点有两个。

第一,可以及时对用户操作作出响应因为一个线程在处理用户输入时,另一个线程在后台完成其他工作,本章开始时所举的拼写检查和打印的例子就是风华正茂的适合多线程技术的应用;第二,如果一个或多个线程所处理的工作不占用CPU时间时,就可以节省时间,比如在经常使用多线程技术的网络应用开发中,让一个线程等待从Internet中获取数据,同时其他线程可以继续处理其他的任务。

<二> 操作线程
1、创建线程
创建线程是Thread类的实例。

Thread类是.NET Framework类库中的类,而且位于System.Threading名称空间中。

因此,为创建Thread类的实例,首先要导入System.Threading名称空间。

然后可以创建代表线程的Thread 类对象。

通过创建Thread类对象的多个实例,就可以在应用程序继承添加线程。

创建线程需要声明Thread类的对象,并提供线程开始执行的方法细节。

为了达到这个目的,需要使用System.Threading名称空间中的public void委托ThreadStart()。

例:创建一个线程并启动
using System.Collections;
using System.Threading;
namespace笔记
{
class MyThread
{
public void Method()
{
Console.WriteLine("创建一个新的线程并启动");
}
public static void MMain()
{
MyThread NewMyThread = new MyThread();
Thread NewThread = new Thread(new ThreadStart(NewMyThread.Method)); //创建新的线程
NewThread.Start(); //启动线程
注意:new ThreadStart()实际上是委托实例。

}
}
}
程序运行结果:
创建一个新的线程并启动
在这里,创建了Thread(线程)类的实例NewThread。

ThreadStart()委托指定了NewThread开始执行的方法是Method,Method是MyThread类中定义的public void函数(方法)。

创建线程后,调用Start()启动线程。

提示:因为可以在多个应用程序中使用定义的线程,因此建议用相关的名称为线程命名,这使得其他程序员可以重用您的线程所提供的功能。

要用相关名称为线程命名,需要修改线程的Name特性值。

下面的代码定义了工作线程,它可以更新主控数据库中的记录,这段代码为线程起了一个有意义的名称,例如Update Records Thread。

Thread MyThread=new Thread(new ThreadStart(newClass.Method));
=“Update Records Thread”;
第一行代码创建了Thread类的实例,其名称是MyThread,然后将名称Update Records Thread赋予线程。

除了可以为线程起有意义的Name属性之外,可以使用特性了解正在执行的线程的状态。

System.Threading 名称空间中的Thread类定义了这些属性。

◆IsAlive属性:IsAlive属性用于确定线程的执行过程是否已经结束或者线程仍然处于执行状态。

对于处
于执行状态的线程,IsAlive特性返回布尔值true,对于没有执行的线程,返回false。

◆ThreadState属性:ThreadStatic属性指出了线程的执行状态。

换句话说,它返回的值说明是否已经开
始执行线程。

2、终止线程*
前面已经介绍了创建和执行线程。

然而,有时可能需要终止正在运行的线程。

仍然考虑前面已经使用过的例子,用打印100页。

在这种情况下,执行线程打印所需要的页面内容。

如果需要打印其他一些急需的页面,则需要停止当前打印命令,或者,换句话说,终止正在打印100页的线程。

C#提供了一个基类Thread,它可以对线程执行几种操作。

Thread包含几个预定义的方法,它们可以处理线程。

为终止线程,要使用Thread类的Abort()方法。

语法如下:
MyThread.Abort()
在这里,MyThread是Thread类的实例。

Abort()方法没有任何参数。

当调用Abort()方法时,C#编译器可能并不会立即终止线程。

要理解为什么C#编译器需要一定的时间来终止线程,首先要理解如何执行Abort()方法。

当调用Thread类的Abort()方法时,线程引发TreadAbortException异常。

除了用于处理线程的基类之外,
处理这种异常。

换句话说,如果尝试在try块内终止正在执行的线程,则C#编译器在终止线程之前首先执行相关的finally块。

可以看到,与立即杀死目标线程的日期环境相比,.NET提供了一种机制,可以更加安全地终止线程。

3、阻塞线程*
C#允许在C#编译器继续执行另一个线程之前,等待某个线程结束执行。

为了达到这个目的,Thread类包含了Join方法来实现。

语法如下:
MyThread.Join();
前面的语句调用Thread类的Join方法,以等待MyThread结束执行。

如果并不知道需要多长时间线程才能结束执行,则可以规定C#编译器在开始执行下一个线程之前等待的最长时间。

如果没有指定最长时间限制,则编译器等待线程自己终止。

Join()方法通常和Abort()方法一起使用。

前面解释过,当调用Abort()方法时,如果线程处于try块中,则不会立即终止线程。

这暗示着,在终止线程之前,需要执行finally语句。

然而,程序员可能并不知道C#编译器执行finally所需要的时候,而且并不准备等待很长的时间。

因此可以调用Abort()方法,然后调用Join()方法,以终止线程。

4、挂起线程
前面已经介绍了如何终止线程。

在终止线程之后,就不能继续执行线程。

然而,当挂起线程时,可以在需要的时候继承执行线程。

暂停执行线程需要使用Suspend()方法。

Suspend()方法是Thread类的另一个方法,而且没有任何参数。

语法如下:
MyThread.Suspend();
Suspend()方法并不会永久杀死线程。

它仅仅在一段时间内停止执行线程,然后可以继续执行。

因此,当需要重新开始执行线程时,要调用Thread类的另一个方法:Resume()方法。

Resume()方法从线程挂起的点开始执行线程。

语法如下:
MyThread.Resume();
与Abort()方法类似,Suspend()方法并不会立即停止执行目标线程。

在挂起线程之前,它等待线程达到安全点。

因此,线程可以调用Suspend()方法挂起本身或者另一个线程。

例如,如果MyThread挂起了本身,则另一个线程需要调用Resume()方法来重新开始执行这个线程。

然而,如果MyThread挂起了另一个线程,如YourThread,则在MyThread在YourThread上调用Resume()方法之前,不会继续执行YourThread。

除了Suspend()方法之外,可以调用Thread类的Sleep()方法阻塞线程的执行。

5、线程休眠
Thread类包含另一个方法Sleep(),将当前线程阻塞指定的毫秒数。

通过作为参数向Sleep()方法传递时间,就可以指定停止线程的时间。

规定时间的单位是毫秒。

下面的这个例子使得线程休眠两秒。

Thread.Sleep(2000);
正如上面的代码所说明的那样,由类本身调用Sleep()方法,而不是类的实例。

<三> 线程优先级
如果在应用程序中有多个程序在运行,但一些线程比另一些重要因而需要分配更多的CPU时间的情况下,可
级较低的线程分配任何时间片,其优点是可以保证给接收用户输入的线程指定较高的优先级。

在大多数的时间内,这个线程什么也不做。

而其他线程则执行它的任务。

但是,如果用户输入了信息,这个线程就会立即获得比应用程序中其他线程更高的优先级,在短时间内处理用户输入数据。

线程的优先级定义为ThreadPriority枚举类型,取值如下表:
高优先级的线程可以完全阻止低优先级的线程执行,因此在改变线程的优先级时要特别小心以免造成某些线程得不到CPU时间。

此外,每个进程都有一个基本优先级,这些值与进程的优先级是有关系的。

给线程指定较高的优先级,可以确保它在该进程内比其它线程优先执行,但系统上可能还运行着其他进程,它们的线程有更高的优先级。

<四> 线程同步
使用线程的一个重要内容是同步访问多个线程访问的任何变量。

所谓同步,是指在某一时刻只有一个线程可以访问变量。

如果不能确保对变量的访问是同步的,就可能会产生错误或不可预料的结果。

一般情况下,当一个线程写入一个变量,同时有其他线程读取或写入这个变量时,就应同步变量。

例如,两个线程thread1和thread2具有相同的优先级,而且同时在系统上运行。

当在时间片中执行第一个线程时,它可能在public变量variable1中写入了某个值。

然而,在下一个时间片中,另一个线程尝试读取或者在variable1中写入某个值。

如果在第一个时间片中没有完成向variable1中的值写入过程,则会产生错误。

当另一个线程读取这个变量时,它可以读取错误的值,这会产生错误。

通过同步使得仅仅一个线程能使用variable1,就可以避免出现这种情况。

通过指定对象的加锁和解锁可以同步代码段的访问。

在.NET的System.Threading命名空间中提供了Monitor 类来实现加锁与解锁。

这个类中的方法都是静态的,所以不需要实例化这个类。

下表中一些静态方法提供了一种机制用来向同步对象的访问从而避免死锁和维护数据一致性。

Monitor类的主要方法
Moinitor.Enter,Monitor.TryEnter和Monitor.Exit用来对指定对象的加锁和解锁。

一旦获取(调用Monitor.Enter)指定对象(代码段)的锁,其他线程都不能获取该锁。

举个例子来说,线程X获得了一个对象锁,这个对象锁可以释放(调用Monitor.Exit(object)or Monitro.Wait())。

当这个对象锁被释放后,Monitor.Pulse方法和Monitor.PulseAll方法通知就线程X获取了锁,同时调用Monitor.Wait的线程X进入等待队列。

当从当前锁定对象的线程(线程Y)收到了Pulse或PulseAll,等待队列的线程就进入就绪队列。

线程X重新得到对象锁时,Monitor.Wait才返回。

以下是使用Monitor类的简单例子:
using System;
using System.Collections;
using System.Threading;
namespace笔记
{
class MyThread
{
public void Method()
{
//获取锁
Monitor.Enter(this);
//处理需要同步的代码
//释放锁
Monitor.Enter(this);
}
}
}
上面的代码运行可能会产生问题。

当代码运行到获取锁与释放锁之间时一旦发生异常,Monitor.Exit将不会返回。

这段程序将挂起,其他的线程也将得不到锁。

解决的方法是:将代码放入try…finally内,在finally 调用Monitor.Exit,这样的话最后一定会释放锁。

C#lock关键辽提供了与Monitoy.Enter和Monitory.Exit同样的功能,这种方法用在代码段不能被其他独立的线程中断的情况。

通过Monitor类的简单封装,lock为同步访问变量提供了一个非常简单的方式,用法如下: lock(x)
{
//使用X的语句
}
lock语句把变量放在圆括号中,以包装对象,称为独占锁或排他锁。

当执行带有lock关键字的复合语句时,独占锁会保留下来。

当变量被包装在独占锁时,其他线程就不能访问该变量。

如果在上面的代码中使用独占锁,在执行复合语句时,这个线程就会失去其时间片。

如果下一个时间片的线程试图访问变量,变会被拒绝。

Windows 会让其他线程处理睡眠状态,直到解除了独占锁为止。

使用lock同步线程示例:
using System;
using System.Collections;
using System.Threading;
namespace笔记
{
//银行账户类
class Account
{
int balance; //余额
Random r = new Random();
public Account(int initial)
{
balance = initial;
}
//取钱
int Withdraw(int amount)
if (balance < 0)
{
throw new Exception("余额为负!");
}
lock (this)
{
if (balance >= amount)
{
Console.WriteLine("原有余额:" + balance);
Console.WriteLine("支取金额:_" + amount);
balance = balance - amount;
Console.WriteLine("现有余额:" + balance);
return amount;
}
else
{
return 0; //拒绝交易
}
}
}
//测试交易
public void DoTransactions()
{
//支取随机金额100次
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}
class TestApp
{
public static void MMain()
{
//建立10个线程同时进行交易
Thread[] threads = new Thread[10];
Account acc = new Account(1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions)); threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}
在这个事例中,10个线程同时进行交易,如果不加控制,很可能发生在支取金额时对balance字段的访问冲突。

假设当前余额为100,有两个线程都要支持60,则各自检查余额时都以为可以支取,造成的后果则是总共支取120,从而导致余额为负值。

读者可以试着将lock语句注释掉再运行,此时将产生余额为负的异常。

独占锁是控制变量访问的许多机制中最简单的。

实际上,C#的lock语句是一个C#语法包装器,它封装了Monitor类的Enter和Exit两个方法的调用。

如果需要进一步了解System.Threading命名空间的其他对象,请参阅MSDN和有关资料。

同步时要注意的问题
同步线程在多线程应用程序中非常重要。

但是,这是一个需要详细讨论的内容,因为很容易出现微妙且难以察觉的问题特别是死锁。

线程同步非常重要,但只要在需要时使用这一条也是非常重要的。

因为这会降低性能。

原因有两个:第一,在对象上放置和解开锁会带来某些系统开销,但这些系统开销都非常小。

第二个原因更为重要,线程同步使用得越多,等待释放对象的线程也就越多。

如果一个线程在对象上放置了一个锁,需要访问该对象的其他线程就只能暂停执行,直到该锁被解开,才能继续执行。

因此,在lock块内部编写的代码越少越好,以免出现线程同步错误。

Lock语句在某种意义上就是临时禁用应用程序的多线程功能,也就临时删除了多线程的各种优势。

另一方面,使用过多的同步线程的危险性(性能和响应降低)并没有在需要时不使用同步线程那么高 (能以跟踪的运行时错误)。

死锁是一个错误,在两个线程都需要访问被互锁的资源时发生。

假定一个线程运行下述代码,其中a 和b 是两个线程都可以访问的对象引用:
lock(a)
{
lock(b)
{
//do something
}
}
同时,另一个线程运行下述代码:
lock(b)
{
loca(a)
{
//do something
}
}
根据线程遇到不同的语句的时间,可能会出现下述情况:第一个线程在a上有一个锁,同时第二个线程在b 上有一个锁。

不久,线程A遇到lock(b)语句,立即进行睡眠状态,等待b上的锁被解开。

之后,第二个线程遇到lock(a)语句,也立即进行睡眠状态,等待windows在a上的锁被解开唤醒它。

但a上的锁永远不会解开,因数第一个线程拥有这个锁,目前正在睡眠状态,在b上的锁被解开前是不会醒的,而在第二个线程被叫醒之前,b上的锁不会解开,结果就是一个死锁。

在上面的代码中发生死锁是非常明显的,在编码中很容易避免,因为程序员肯定不会编写这样的代码,但记住不同的锁可以发生在不同的方法调用中。

在这个示例中,第一个编程实际执行下述代码:
locak(a)
{
CallSomeMethod();
}
CallSomeMethod()可以调用其他方法,其中有一个locak(b)语句,此时是否会发生死锁就不那么明显了。


编写式线程应用程序时,如果需要同步,就必须考虑代码的所有部分,检查是否有可能发生死锁的条件。

必须记住:不可能预见不同线程遇到不同语句的确切时间。

在应用程序中使用多线程要仔细规划,太多的线程会导致资源问题,线程不足又能会使需要处理多任务的应用程序执行缓慢,执行效果不好。

虽然.NET Framework提供了处理线程的各种方法与机制,但并没有解决处理线程中所有困难的任务,如我们必须考虑线程的优先和同步问题。

<五> 线程常用类
5.1 Thread类
System.Threading.Thread类是创建并控制线程,设置其优先级并获取其状态最为常用的类。

Thread类的公共属性如下表。

在Thread类中,Priority是一个很重要的属性,它用于获取或设置任何线程的优先级。

System.Threading.Thread.Priority枚举了线程的优先级别,从而决定了线程能够得到多少CPU时间。

高优先级的线程通常会比一般优先级的线程得到更多的CPU时间,如果不止一个高优先级的线程,操作系统将在这些线程之间循环分配CPU时间;低优先级的线程得到的CPU时间相对较少,当没有高优先级的线程时,操作系统将挑选下一个低优先级的线程执行。

一旦低优先级线程在执行时遇到了高优先级的线程,这让出CPU给高优先级的线程。

新创建线程的优先级一般优先级,可以设置线程的优先级别如下表。

System.Threading.Thread.ThreadState属性定义了执行时的线程状态,线程从创建到终止,一定处于其中一个状态。

当线程创建时,它处于Unstarted状态。

Thread类的Start()方法将使其变为Running状态,线程将一直处于这样的状态;除非我们调用相应的方法使其挂起、阻塞或者自然终止。

如果线程挂起,它将处于Suspended状态;除非我们调用resume()方法使其重新执行,这时线程将重新变为Running状态。

一旦线程被销
毁或者终止,则处于Stopped状态,处于这个状态的线程将不复存在。

正如线程开始启动,则不可能回到Unstarted 状态。

线程还有一个Background状态,它它表明线程运行在前台不定式是后台。

在一个确定的时间,线程可能处于多个状态。

举例来说,一个线程被调用了Sheep而处于阻塞,而接着另外一个线程通过Abort方法调用这个阻塞的线程,这时线程将同时处于WaitSleepJoin和AbortRequested状态。

一旦线程响应转为Sle阻塞或者中止,当销毁时会抛出ThreadAbortException异常。

5.2 Mutex类
当两个或更多线程需要同访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。

Mutex是同步基元,它只向一个线程授予对共享资源的独占访问权。

如果一个线程获取了互斥,则要获取该互斥体的第2个线程挂起,直到第1个线程释放该互斥体。

Mutex类比Monitor类使用更多的系统资源,但是它可以跨应用程序域边界进行封送处理,可用于多个等待并同步不同进程中的线程。

一个线程可以通过调用WaitHandle.WaitOne或WaitHandle.WaitAny或WaitHandle.WaitAll得到Mutex的拥有权。

如果Mutex不属于任何线程,上述调用将使得线程拥有Mutex ,而且WaitOne会立即返回。

但是如果有其他线程拥有Mutex,WaitOne将陷入无限期的等待,直到获取Mutex。

可以在WaitOne方法中指定参数,即等待的时间而避免无限期的等待,调用Close作用于Mutex 将释放拥有。

一旦Mutex 被创建,即可通过GetHandle 方法获得Mutex的句柄,而给WaitHandle.WaitAny或WaithHandle.WaitAll方法使用。

Mutex公共方法
使用ReleaseMutex()方法释放Mutex一次,拥有互斥体的线程可以在重复等待函数调用中指定相同的互斥体而不用阻塞其执行,调用次数由运行库保存。

线程必须调用与ReleaseMutex方法相同的次数以释放互斥体的所属权。

如果线程在拥有互斥体期间正常终止,则互斥体状态设置为终止,并且下一个等待线程获得所属权。

如果没有线程拥有互斥体,则互斥体状态为终止。

示例:
Using System;
Using System.Threading;
Class Test
{
Private static Mutex mut=new Mutex(); //创建一个Mutex对象
Private const int numIterations=1;
Private const int numThreads=3; //设置线程数量为3
Static void Main()
{
//创建线程,该线程将访问共享资源
for (int i=0;i<numThreadings;i++)
{
//创建线程
Thread myThread=new Thread(new ThreadStart(MyThreadProc));
=String.Format(“Thread{0}”,i+1);
myThread.Start(); //启动线程
}
}
Private static void MyThreadProc()
{
for (int i=0;i<numIterations;i++)
{
UseResource(); //使用共享资源。

}
}
Private static void UseResource()
{
//阻塞当前线程,直到线程安全进入
mut.WaitOne();
Console.WriteLine(“{0}已进行保护区域”,);
//模拟一些工作
//线程阻塞
Thread.Sleep(500);
Console.WriteLine(“{0}正在离开保护区域”,);
mut.ReleaseMutex(); //释放Mutex对象
}
}
5.3 ReaderWriterLock类
ReaderWriterLock类定义支持单个写线程和多个读线程锁,用于同步对资源的访问。

在任一特定时刻,它允许多个线程同时进行读访问,或者允许单个线程进行写访问。

在资源不经常发生更改情况下,ReaderWriterLock 类所提供的吞吐量比简单的一次只允许一个线程的锁更高。

ReaderWriterLock类支持以下功能。

(1)大量用于针对每个对象的同步活动中。

(2)超时用来检测死锁。

(3)事件缓存可以使用时间从争议最小的区域移动到争议最大的区域,ReaderWirterLock需要的事件数由进程中的线程数限定。

(4)由阅读器和编写器嵌套的锁。

(5)用于避免在多处理器计算机上进行上下文切换的旋转计数。

(6)编写器锁的升级和降级,升级到编写器锁将返回指示中间写入的参数,而从编写器锁降到还原锁的状态。

(7)用于释放锁以便线程可以调用应用程序代码的方法,还原锁的状态并指示中间写入。

(8)从最常见的失败(如创建事件)中恢复,锁将维护一致的内部状态并且保持可用。

ReaderWriterLock公共属性
5.4 ThreadPool类
如果有多个任务需要完成,每个任务需要一个线程,这时应该考虑使用线程池来更有效地管理计算机资源并且从中受益。

线程池是执行的多个线程集合,它允许系统添加以线程自动创建和开始的任务到队列中,使用线程池使得系统可以优化线程在CPU使用时的时间碎片。

但是要记住在任何特定的时间点,每一个进程一每个线程池只有一个个正在运行的线程。

使用ThreadPool类可以使得由线程组成的池可以被系统管理,而使开发人员主要精力集中在工作流的逻辑,而不是线程管理上。

ThreadPool类提供了一个线程池,该线程池通用于发送工作项、处理异步I/O、代表其他线程等待,以及处理计时器。

很多应用程序创建的线程都要在休眠状态中消耗大量的时间以等待事件的发生,其他线程可能进行休眠状态,只被定期唤醒以轮询更改或更新状态信息。

TheadePool类的公共方式
示例:
Public class Example
{
Public static void Main()
{
//唤醒线程,并将用户工作项排队到线程池
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
……
}
Static void ThreadPro(Object stateInfo)
{
Console.WriteLine(“Hell from the thread pool”);
}
}
5.5 WaitHandle类
WaitHandle类封装等待共享资源的独占访问权的操作系统特定的对象,通常用做同步对象的基类。

从该类派生的类定义一个信号传输机制以指示获取或释放对共享资源的独占访问,但使用继承的WaitHandle方法在等待对共享资源的访问时阻塞。

使用此类的静态方法阻塞刈割线程,直到一个或多个同步对象接收到信息。

5.5 AutoResetEent类
AutoResetEvent类通知正在等待的线程已发生事件,无法继承此类。

AutoResetEvent类允许线程通过发信号互相通信,通常此通信涉及线程需要独占访问的资源。

AutoResetEvent类将始终保持终止,直到一个正在等待的线程被释放,此时系统将自动把状态设置为非终止状态。

如果没有任何线程丰等待,则状态将保持为终止状态。

相关文档
最新文档