活动:
|
目的
|
|
角色:软件设计人员 | |
频率:每个迭代一次,特别是在精化阶段期间。 | |
步骤 | |
输入工件: | 生成的工件: |
工具向导: | |
更多信息: |
工作流程明细: |
活动对象(即,活动类的实例)用于代表系统中的并发执行线程:从理论上来讲,每个活动对象都有其自己的控制线程,而且按照惯例是执行堆栈框架的根。将活动对象映射到实际的操作系统线程或流程可能因响应需求的不同而不同,并且将受环境切换开销考虑事项的影响。例如,与简单调度程序合并的一些活动对象可能会共享单个操作系统线程,从而造成并发运行的现象。但是,如果任何活动对象表现出阻塞行为(例如,通过执行同步输入-输出),那么组中的其它活动对象将无法对在操作系统线程被阻塞时发生的事件作出反应。
另一个极端是,如果处理资源不受额外环境切换开销的负面影响,那么对每个活动对象都给予它自己的操作系统线程应该会带来更高的响应度。
此活动从活动类及其实例以及它们与操作系统线程和流程的关系的角度为系统定义流程体系结构。
在“精化”阶段早期,该体系结构将是相当初步的,但到了“精化”阶段后期,进程和线程应该有了很好的定义。
此活动的结果记录在设计模型中 - 更具体地说,是在流程视图中(请参阅概念:流程视图)。
目的 | 定义系统所要求的任务并行执行的程度。该定义将有助于塑造体系结构。 |
在活动:确定设计元素期间,考虑的是基本由对问题领域中的并行自然产生的需求而驱使的并行需求。
这样得到的结果是一组活动类,代表系统中的逻辑控制线程。
在本步骤中,我们考虑并行需求的其它来源 - 那些由系统的非功能需求强加的并行需求。
并行需求由以下内容驱使:
与许多体系结构问题一样,这些需求可能存在轻度的互斥。出现互相冲突的需求(至少一开始时)并不少见。根据重要性评定需求等级将有助于解决冲突。
目的 | 定义将在系统中存在的进程和线程。 |
最简单的方法是将所有活动对象分配给公共线程或流程,并使用简单的活动对象调度程序,因为这样能将环境切换的开销降到最低。但是,在某些情况下,可能有必要将活动对象分发到一个或多个线程或流程之间。
如果与其它活动对象共享操作系统线程的活动对象对某个其它的进程或线程发出了同步调用,而且该调用阻碍了调用对象的共享操作系统线程,那么这将自动暂挂位于调用流程中的所有其它的活动对象。现在就不一定会出现这种情况了:从活动对象的角度看是同步的调用在控制活动对象组的简单调度程序看来可能是不同步处理的 - 调度程序暂挂发出调用的活动对象(等待其同步调用的完成),然后调度其它活动对象运行。
当原始的“同步”操作完成时,发出调用的活动对象就可以恢复了。但是,这种方法并非总是可用,因为它对于以下调度程序可能不可行:这样的调度程序被设计为拦截所有同步调用(不管这些调用会不会阻塞)。请注意,使用同一个操作系统进程或线程的活动对象之间的同步调用可能(在一般情况下)会被调度程序用这种方法进行处理 - 而且,在发出调用的活动对象看来,在效果上与过程调用相同。
这使我们得出这样的结论:活动对象应该根据它们与阻塞线程的同步调用并发运行的需要来分组为进程或线程。也就是说,活动对象应与另一个使用阻塞线程的同步调用的对象封装到同一个进程或线程中的唯一可能是:它不需要与该对象并发执行,并且可以容忍不在其它对象受阻时执行。在极端的情况下,当响应性很关键的时候,这可能会造成有必要为每个活动对象安排独立的线程或进程。
作为一个一般规则,在上述情形中,使用轻量级线程比使用成熟的进程更好,因为这样涉及的开销要少。但是在一些特殊的情况下,我们可能还是希望利用进程的一些特殊特征。既然线程共享同一个地址空间,它们内在地就比进程有更大的风险。如果担心意外覆盖的可能性,那么就最好选择进程。而且,因为进程在大多数操作系统中代表独立的恢复单元,所以根据活动对象彼此独立恢复的需要将它们分配给进程可能会很有用。也就是说,需要恢复为一个单元的所有活动对象都可以一起封装到同一个进程中。
请为系统需要的每一个独立的控制流创建一个进程或线程(轻量级进程)。线程应该在需要嵌套的控制流的情况下使用(即,如果在进程内的子任务级别上需要独立的控制流)。
例如,我们可以说(不一定按照重要性排列)独立的控制线程可能需要用来:
示例
在自动柜员机中,必须处理来自三个不同来源的异步事件:系统的用户、ATM 设备(例如当自动取款机出现拥堵时)或者 ATM 网络(当网络发出关闭伪指令时)。要处理这些异步事件,我们可以在 ATM 本身中定义三个独立的执行线程,如下面用 UML 的活动类所显示。
ATM 中的进程和线程
目的 | 确定进程和线程在何时创建与销毁。 |
每个控制进程或线程都必须创建和销毁。但单进程体系结构中,进程在应用程序启动时创建,在应用程序结束时销毁。在多进程体系结构中,新的进程(或线程)一般从在应用程序启动时由操作系统创建的第一个进程中衍生或派生。这些进程也必须明确地销毁。
必须确定并记录导致进程创建和销毁的事件的顺序(以及创建和删除的机制)。
示例
在自动柜员机中,会启动一个负责协调整个系统的行为的主要进程。它接着衍生一些下级控制线程来监视系统的各个部分:系统中的设备以及从客户和 ATM 网络发出的事件。这些进程和线程的创建可以用 UML 的活动类来显示,而这些活动类的实例的创建可以用序列图来显示,如下所示:
系统启动期间进程和线程的创建
目的 | 确定进程和线程将交流的方法。 |
进程间通信(IPC)机制使消息能够在独立进程中执行的对象间发送。
典型的进程间通信机制包括:
选择 IPC 机制将改变系统建模的方式;例如,在“消息总线体系结构”中,没有必要让对象间的明确关联发送消息。
目的 | 分配稀缺资源 预测和管理潜在的性能瓶颈 |
进程间的通信机制一般很稀有。信号、共享内存和邮箱一般大小或数量固定,而且不花大成本就不可能增加。RPC、消息和事件广播越来越多地吸收稀缺的网络带宽。当系统超过资源阈值时,它一般会经历非线性的性能下降:一旦稀缺资源用完了,那么后来对它的请求就可能会有不尽人意的效果。
如果对稀缺资源的需求过量,就可以考虑几个策略:
一旦部署了系统,那么不管选择了什么策略,系统都应该温和地降级(而不是崩溃),而且应该向系统管理员提供足够的反馈,使问题当场得到解决(如果可能的话)。
如果系统要求运行时环境有特殊的配置才能提高关键资源的可用性(通常由重新配置操作系统内核来控制),那么系统安装就需要自动进行特殊配置,或者指示系统管理员这么做,系统才能变得可以操作。例如,系统可能需要重新引导,更改才能生效。
目的 | 将“控制流”映射到受实施环境支持的概念上。 |
概念进程必须映射到操作环境中的特定构造上。在许多环境中都可以选择进程类型,至少通常可以选择进程和线程。选择将根据耦合程度(进程是独立的,而线程在封闭进程的环境中运行)以及系统的性能要求(线程间的进程间通信一般比进程间的进程间通信更快速、更有效)来作出。
在许多系统中,每个进程可能有最大量的线程,或者每个节点有最大量的进程。这些限制可能不是绝对的,但可能是由于稀缺资源的可用性而强加的实际限制。需要考虑的是已经在目标节点上运行的线程和进程,以及进程体系结构中提议的线程和进程。较早的分配进程间的协调资源步骤的结果需要在映射完成时考虑,以确保没有引起新的性能问题。
目的 | 确定类和子系统应该在哪些控制线程内执行。 |
给定的类或子系统的实例必须至少在一个为类或子系统提供执行环境的控制线程内执行;它们实际上可以在数个不同的进程中执行。
我们同时用两个不同的策略,就可以确定并行的“正确”数量,并可以定义“正确”的进程组:
这不是会带来最佳进程视图的线性的、确定性的过程;它要求一些迭代达到可接受的妥协。
示例
下图说明 ATM 中的类如何在系统中的进程和线程间分发。
ATM 的类到进程的映射
Rational Unified Process
|