RSS

导航







快速搜索

高级搜索 »

注意:此页面是Spring.NET框架 1.1 参考文档的一部分。


编辑

7.1. 简介

Spring.Threading命名空间的目的,是用一系列功能强大的抽象来增强FCL中的相关功能。由于Doug Lea在他的java版EDU.oswefo.cs.dl.util.concurrent类库中已经定义了很多用于并发操作的成熟类型,所以我们决定将其中的一部分导入到Spring.NET中来。到目前为止我们只导入了3个类,包括用来支持AOP池化方面(AOP based pooling aspect)、提供对象池基本功能的类和Semaphore类(.NET 1.0/1.1没有相应的类型,2.0中新增了Semaphore类)。

另外,在Java 5中,java.util.concurrent包中的类也建立在Doug Lea的类库之上,并且已经通过了严格的审查。Java 5类库及.NET 2.0中新增的类型有可能导致Spring在这方面进行修改。

Spring.Threading中还有一个很重要的工具类LogicalThreadContext,用于进行线程的本地存储。

顶部

编辑

7.2. 线程本地存储

根据运行环境的不同,在线程本地存储中保存对象也需要应用不同的策略。在Web应用程序中,如果一个请求可能会被多个线程处理,线程局部对象就应该保存在HttpContext.Current中。其它情况则可使用 System.Runtime.Remoting.Messaging.CallContext。这两种策略的选择依据,以及与 [ThreadStatic]特性的比较可以参考“Piers7”的blog和Spring.NET的论坛。而LogicalThreadContext则把这方面的细节隐藏了起来,所以可以使代码更具可移植性。

LogicalThreadContext类的定义相当简单:

public sealed class LogicalThreadContext
{
 public static object GetData(string name)

 public static void SetData(string name, object value)

 public static void FreeNamedDataSlot(string name)

}

该类定义了一系列静态方法,可以用字符串作为键值设置或读取数据。如果想要释放存储区的空间,可以调用FreeNamedDataSlot方法。

顶部



编辑

7.3. 同步基础

用户可能会很奇怪,既然System.Threading已经提供了那么多用于同步的类,为什么Spring.NET还要定义这些同步类型呢?这是因为System.Threading中的相关类型虽多,却没有为我们提供一个优雅的抽象或接口,我们只能在一个很低的层面编写代码。凭经验来讲,要让代码工作的好,我们最终还是得拿出一个抽象层次来。Doug Lea已经在这方面作了很多研究,我们可以充分的利用他的研究成果。

顶部

编辑

7.3.1. ISync

ISync是所有用于控制多线程资源访问的类的核心接口。这个接口很简单,主要有两种基本的用途。第一种是用来阻塞当前线程,直到满足了某个条件:

void ConcurrentRun(ISync lock) {
 lock.Acquire(); // block until condition met
 try {
 // ... access shared resources
 }
 finally {
 lock.Release();
 }
}

另一种是用来指定在满足某个条件前将线程阻塞的最多次数:

void ImpatientConcurrentRun(ISync lock) {
 // block for at most 10 milliseconds for condition
 if ( lock.Attempt(10) ) {
 try {
 // ... access shared resources
 }
 finally {
 lock.Release();
 }
 } else {
 // complain of time out
 }
}

顶部

编辑

7.3.2. SyncHolder

SyncHolder类实现了System.IDisposable接口,利用这个类我们可以在c#的using语句中使用ISync接口:进入 using语句后ISync的Acquire方法会自动调用,退出using语句后ISync的Release方法会被自动调用。

使用using语句可以简化编程模型,请看下面的例子:

ISync sync = ...
...
using (new SyncHolder(sync))
 {
 // ... code to be executed
 // holding the ISync lock
 }

当然这是同步版本(按:timed version), 如果要自己处理超时,就稍微麻烦一点儿:

ISync sync = ...
long msecs = 100;
...
// try to acquire the ISync for msecs milliseconds
try 
{
 using (new SyncHolder(sync, msecs))
 {
 // ... code to be executed
 // holding the ISync lock
 }
} 
catch (TimeoutException)
{
 // deal with failed lock acquisition
}


编辑

7.3.3. Latch

Latch类实现了ISync接口,它是一个闭锁。闭锁是一个布尔条件,最多只能设置一次。一旦闭锁开放,所有等待着的线程都会解除阻塞。这就如同一个初始状态设置为非终止的ManualResetEvent对象(即创建时传给构造器的参数值为false,或者调用Reset将事件状态设置为非终止状态,从而导致其它线程阻塞)一样,只有在调用了Set()方法将事件状态设为终止之后,才能允许其它等待着的线程继续执行。Latch典型的用法是作为一组工作线程的开始信号。

class Boss {
 Latch _startPermit;

 void Worker() {
 // very slow worker initialization ...
 // ... attach to messaging system
 // ... connect to database
 _startPermit.Acquire();
 // ... use resources initialized in Mush
 // ... do real work
 }

 void Mush() {
 _startPermit = new Latch();
 for (int i=0; i<10; ++i) {
 new Thread(new ThreadStart(Worker)).Start();
 }
 // very slow main initialization ...
 // ... parse configuration
 // ... initialize other resources used by workers
 _startPermit.Release();
 }

}

顶部

编辑

7.3.4.信号量

Semaphore类实现了ISync接口,实现了信号量的功能。从概念上说,信号量维护了一组许可证,用来控制允许同时进入同步代码的线程数。每次Acquire方法调用都需要等待有一个许可证变为可用,然后便占用此许可证。每次调用Release方法后都会释放一个许可证。其实 Semaphore并没有使用实际的“许可证”对象,只是在内部维护了一个许可证的可用数量。最典型的用法是控制对共享对象池的访问。

class LimitedConcurrentUploader {
 // ensure we don't exceed maxUpload simultaneous uploads
 Semaphore _available;
 public LimitedConcurrentUploader(maxUploads) {
 _available = new Semaphore(maxUploads);
 }
 // no matter how many threads call this method no more
 // than maxUploads concurrent uploads will occur.
 public Upload(IDataTransfer upload) {
 _available.Acquire();
 try {
 upload.TransferData();
 }
 finally {
 _available.Release();
 }
 }
}

顶部



.NET 藏经阁 | | 版权所有 ©2008 entlib.net.cn