进程、线程和单元

进程 是虚拟内存空间、代码、数据和系统资源的集合。 线程 是在进程中串行执行的代码。 处理器执行线程,而不是进程,因此每个应用程序至少有一个进程,并且一个进程始终至少有一个执行线程,称为主线程。 除了主线程之外,进程还可以有多个线程。

进程通过消息相互通信,使用 Microsoft 的远程过程调用 (RPC) 技术相互传递信息。 来自远程计算机上的进程的调用与来自同一计算机上的另一个进程的呼叫之间没有区别。

当线程开始执行时,它会一直持续到它被终止,或者直到它被优先级较高的线程中断(由用户作或内核的线程计划程序中断)。 每个线程可以运行单独的代码部分,或者多个线程可以执行相同的代码部分。 执行同一代码块的线程维护单独的堆栈。 进程中的每个线程共享该进程的全局变量和资源。

线程计划程序根据进程的优先级类属性和线程的基本优先级的组合来确定执行线程的时间和频率。 通过调用 SetPriorityClass 函数来设置进程的优先级类属性,并通过调用 SetThreadPriority设置线程的基本优先级。

多线程应用程序必须避免两个线程问题:死锁争用。 当每个线程正在等待另一个线程执行某些作时,将发生死锁。 COM 调用控件有助于防止对象之间的调用中的死锁。 当一个线程在它依赖的另一个线程之前完成,导致前者使用未初始化的值,因为后者尚未提供有效的值时,会出现争用条件。 COM 提供了一些专为帮助避免进程外服务器中的争用条件而设计的函数。 (请参阅 进程外服务器实现帮助程序

单元和 COM 线程体系结构

虽然 COM 支持在引入多个线程之前普遍存在的单线程每进程模型,但你可以编写代码来利用多个线程,从而产生更有效的应用程序,方法是允许执行一个线程,而另一个线程等待一些耗时的作完成。

注意

使用多个线程不能保证性能更好。 事实上,由于线程分解是一个难题,因此使用多个线程通常会导致性能问题。 密钥是仅当非常确定正在执行的作时,才使用多个线程。

 

一般来说,查看 COM 线程体系结构的最简单方法是将进程中的所有 COM 对象视为分为称为 单元的组。 COM 对象正好位于一个单元中,从某种意义上说,其方法只能由属于该单元的线程直接调用。 要调用该对象的任何其他线程都必须通过代理。

有两种类型的公寓:单线程公寓多线程公寓

  • 单线程单元只包含一个线程,因此生活在单线程单元中的所有 COM 对象只能从属于该单元的一个线程接收方法调用。 对单线程单元中 COM 对象的所有方法调用都与单线程单元线程的 Windows 消息队列同步。 具有单个执行线程的进程只是此模型的一个特殊情况。
  • 多线程单元由一个或多个线程组成,因此生活在多线程单元中的所有 COM 对象都可以直接从属于多线程单元的任何线程接收方法调用。 多线程单元中的线程使用名为 自由线程的模型。 对多线程单元中的 COM 对象的调用由对象本身同步。

注意

有关同一进程中单线程单元与多线程单元之间的通信的说明,请参阅 Single-Threaded 和多线程通信

 

一个进程可以有零个或多个单线程单元和零个或一个多线程单元。

在此过程中,主单元是第一个初始化单元。 在单线程进程中,这是唯一一个单元。 调用参数在单元之间封送,COM 通过消息传送处理同步。 如果将进程中的多个线程指定为自由线程,则所有免费线程都驻留在单个单元中,参数将直接传递到单元中的任何线程,并且必须处理所有同步。 在具有自由线程和单元线程处理的过程中,所有免费线程都驻留在单个单元中,所有其他单元都是单线程单元。 执行 COM 工作的过程是单元集合,其中最多包含一个多线程单元,但任意数量的单线程单元。

COM 中的线程模型为使用不同线程体系结构协同工作的客户端和服务器提供机制。 自然支持在不同进程中具有不同线程模型的对象之间的调用。 从调用对象的角度来看,无论调用的对象是如何被线程调用的,对进程外部的对象的所有调用的行为都相同。 同样,从被调用的对象的角度来看,无论调用者的线程模型如何,到达调用的行为都相同。

客户端和进程外对象之间的交互非常简单,即使它们使用不同的线程模型,因为客户端和对象位于不同的进程中。 在客户端和服务器之间交错的 COM 可以使用标准封送和 RPC 为线程模型提供可互作的代码。 例如,如果多个自由线程客户端同时调用单线程对象,则 COM 将通过在服务器的消息队列中放置相应的窗口消息来同步调用。 每次检索和调度消息时,对象的单元都会收到一个调用。 但是,必须谨慎确保进程内服务器与其客户端正确交互。 (请参阅 In-Process 服务器线程问题。)

使用多线程模型编程时最重要的问题是使代码线程安全,以便特定线程的消息仅转到该线程,并且对线程的访问受到保护。

有关详细信息,请参阅以下主题: