翻译,原文:http://help.agi.com/AGIComponents/html/Multithreading.htm
STK组件是为多线程设计的。它执行的许多操作,例如预报和计算过境,都是使用多个线程自动并行执行的,这使库能够充分利用现代多核处理器。
与STK组件的其他库相比,Insight3D具有不同的线程策略,请参见下面的Insight3D部分。
STK组件中的线程
你可以通过更改线程策略ThreadingPolicy
来控制STK组件对线程的使用。线程策略是与每个线程关联的配置信息,它控制该线程启动的可并行操作如何使用线程。默认情况下,策略指定可并行操作为系统上的每个逻辑处理器创建一个线程。例如,如果你的系统有四个内核,并且每个内核都是超线程的(意味着它支持两个硬件线程),那么STK组件将自动创建并使用八个线程来计算过境、覆盖率等。
通过设置NumberOfThreads
属性,可以指定要使用的线程数。例如,下面的代码指定当前线程创建的可并行操作应该只使用五个线程来执行它们的工作。
ThreadingPolicy.NumberOfThreads = 5;
你还可以通过将NumberOfThreads
设置为1或调用ConfigureTouseCurrentThreadOnly
方法完全禁用多线程。当线程策略配置为仅使用一个线程时,可并行操作将使用调用线程执行,并且不会创建其他线程。
ThreadingPolicy.ConfigureToUseCurrentThreadOnly();
根据ThreadSource
属性的值,可以从线程池中招募新线程,也可以显式创建新线程供可并行操作使用。默认情况下,线程从线程池中招募。以下代码更改属性,以便创建新线程:
ThreadingPolicy.ThreadSource = ThreadSource.NewThread;
从线程池中招募线程通常比直接创建线程快得多。但是,有时避免使用线程池是有用的,这样线程池就不会被长时间运行的操作独占。
线程安全
这种库范围内的多线程处理需要在整个库中小心地注意线程安全。需要注意一个类型对于多个线程同时使用什么时候是安全的,什么时候是不安全的。
一般来说,STK组件中的所有类型(除Insight3D之外,见下文)都是只读访问的线程安全类型。换句话说,只要方法和属性不修改对象的状态,就可以从多个线程同时调用方法和访问实例的属性。但是,如果一个线程在另一个线程读取属性或执行方法时修改对象,则第二个线程可能会遇到对象的不一致状态,或者对象可能会引发异常。
此外,静态方法和属性可以从多个线程同时使用。此外,可以从多个线程同时使用同一类型的两个不同实例。并且只要你确保一次只有一个线程访问它,就可以从任何线程(甚至多个线程)自由地使用单个实例。在极少数情况下,这些规则的例外情况将在参考文件中明确说明。
STK组件中的某些类型(尤其是Evaluator)实现了IThreadAware
接口。实现此接口的类型对于只读访问甚至可能不具有线程安全性,如上所述。如果此接口上的IsThreadSafe
属性返回true
,则可以假定实例与stk组件中的大多数对象一样具有线程安全性;只要没有线程修改实例,则可以同时使用多个线程中的实例。但是,如果返回false
,则在任何情况下都不能同时从多个线程使用该实例。
幸运的是,实现IThreadAware
的所有类型也实现ICloneWithContext
,这意味着您可以使用CopyForAnotherThread
来制作实例的副本。然后,可以同时从多个线程使用原始线程和任何副本。此外,只要没有线程同时修改实例,就可以安全地从多个线程同时复制另一个线程的实例。
以下代码创建一个PointEvaluator
(实现IThreadAware
)来计算点的位置,然后准备将其传递给新线程:
PointEvaluator evaluator = point.GetEvaluator();
PointEvaluator evaluatorForNewThread = CopyForAnotherThread.Copy(evaluator);
CopyForNotherThread
可以安全地用于实现IThreadAware
的任何类型,不管它是否报告自己是线程安全的。当对线程安全的类型调用CopyForNotherThread.copy<T>
时,它将返回现有实例,而不进行其他副本。
InSight3D
InSight3D目前不支持多线程。所有与InSight3D类型的交互都必须从单个线程完成。即使用户确保一次只有一个线程与InSight3D交互,也不能保证从多个线程使用insight3d类型是安全的。