Intro: Heroius.Extension.Box

1. 问题源起

Heroius.Extension.Box 库中包含了几个类型,最早是用于分隔公用变量。所谓“公用变量”,是指编程语言中使用的生命周期长、作用域广的变量,如在托管平台上类中的static成员、Fortran的Module成员等。对公用变量的“分隔”是指在运行包含公用变量的代码的多个实例时,采取某些措施,使得各运行实例中的公用变量彼此独立、互不干涉。亦即,这些公用变量一般来说在一个程序实例中保持一个副本,所有操作都会在同一内存上生效;而“分隔”让这些公用变量的行为变得和实例成员一样,可以有多个副本单独保存值。

在一般开发中不需要这种分隔技术,因为用户可以运行多个程序实例。但是当制作以多任务形式调用现有应用时,则需要考虑此类变量的独立。例如ASP.NET应用只拥有一个应用程序域,static成员对所有session都是一样的。为了应对此类场景,在Heroius.Extension.Box中设置了两套类型,分别处理.net framework托管代码的static成员和现有命令行程序。

2. 利用应用程序域分隔的StaticBox

.Net平台上的应用程序是由应用程序域(AppDomain)相互隔离的,利用新建应用程序域并加载包含静态成员的类可以实现公用变量分隔。

StaticBox适用于:含有static成员(S)的程序集(A)、且使用该成员的类型为实例类(C),在该类的非静态方法(M)中使用static成员(S)。StaticBox对指定的类型(C)进行跨应用程序域封装,其上的所有非静态方法(M)都作为一个StaticBoxJob类型实例,能够跨应用程序域调用。在多个StaticBox实例中,调用的方法(M)彼此之间的变量分属于不同的应用程序域,由此实现隔离。

3. 利用进程分隔的ConsoleBox

进程是最高的分隔单位,也是对非托管平台进行分隔的唯一方法。

ConsoleBox适用于:命令行代码生成的执行程序(A),代码中使用了公用模块,以至于通过混合编程多次调用时会导致变量覆盖。ConsoleBox实现了命令行进程的封装,以后台模式运行程序(A),对其用户等待状态提示进行侦听、其输入输出进行重定向,其侦听、完成均以事件形式通知。且ConsoleBox支持中断执行和等待进程完成。另外还有:ConsoleAutoJob类,可实现进一步封装,顺序执行多个命令行程序,且在交互式命令行程序中,可预先设计交互文本,执行完成后,从缓存属性中一次性获取所有输出;ConsoleJobManager类,可对多个相同执行任务的ConsoleAutoJob实例进行管理,使各实例运行在不同工作目录下,避免输入、输出文件相互干扰。

注意:由于重定向输入无法完成键盘模拟,因此上述执行程序(A)不得包含用户按键输入等待,形如 getchar、ReadKey 的调用。当遇到此类调用时,ConsoleBox 将因错误自动中断执行。

3.1 关于命令行程序的用户等待状态识别

在命令行程序执行过程中,用户只能在主线程空闲时进行输入,但是命令行外壳本身不会对可以输入的状态进行事件通知。在 Stackoverflow问题页 中,提示通过轮询命令行程序的所有线程,识别其中是否出现System.Diagnostics.ThreadState.Wait状态,且为WaitReason.UserRequest,来判断进程是否在等待用户输入。但通过实际测试,运行后台命令行的进程会创建9~10个线程,且其状态与用户输入时机无关(总是会有满足上述判定条件的线程存在,即便在进程执行长时间任务时,且在执行任务空闲后状态没有明显变化)。

命令行输入流本身可以将输入缓存,笔者猜测其本身不具备输入等待的确切事件,当界面线程空闲时,会自动从输入流获取消息,此过程无法被外界以无影响的形式探知。唯一的探知方法就是尝试向输入流写入,然后在判断此流的内容是否被取走。但是此种方法会干预输入内容本身,类似于“测不准原理”的情形,因此是无法采用的。

基于上述分析,只能采取根据输出内容判断输入时机的方法,ConsoleBox 的构造函数接受名为 InputPrompts 的字符串数组,作为与输出进行匹配的判断条件,当匹配时触发一次输入。在ConsoleAutoJob 的 Execute 方法参数中,接受 ConsoleAutoJobExecutionConfig 数组,其中包含输入时机的判定文本及输入文本配置。

4. 获取Heroius.Extension.Box

可在 nuget.org 搜索查询到此库。此文基于版本2.0。

发表评论

电子邮件地址不会被公开。 必填项已用*标注


9 + = 十四