COBOL 在多线程编程中的局限性

企业和政府机构通常需要使用多线程应用程序来加快 COBOL 程序的运行。在现实中,COBOL 多线程本身存在一些局限性。在本文中,作者将解释这些局限性以及如何处理它们。

Judith M. Myerson, 系统工程师兼架构师

Judith M. Myerson 是一位系统工程师兼架构师。她感兴趣的领域包括中间件技术、企业级系统、数据库技术、应用程序开发、网络管理、安全性、 RFID 及时和项目管理。她是 RFID in the Supply Chain 的作者,也是 Enterprise Systems Integration, Second Edition Handbook 的编辑。



2011 年 8 月 15 日

概述

多线程允许一个设计良好的程序中的每个任务可以彼此独立运行,并且几乎是同时运行。在多个 CUP(双核或四核)上运行多个线程可以改善性能。多线程应用程序也可以在单 CPU 系统上工作,但是无法实现提速。

在过去几年中,我见证了 COBOL 程序的演变过程:最初是在旧的 IBM 主机上的一个单线程中运行,按照现在的标准,其速度非常慢,而目前,COBOL 程序可以在更快、更小的机器上的多个线程中运行。COBOL 的创始人,同时也是本文作者的论文导师,海军少将 Navy Rear Admiral Grace Hopper 应该会非常高兴看到 IBM COBOL for AIX。

在多线程上运行 COBOL 程序的基本要点就是必须使用 THREAD 编译器选项对所有 COBOL 程序进行编译。同一个程序可以有不同的线程,例如,一个线程用于执行程序的某个任务,另一个线程用于执行同一程序的第二个任务,等等。

需要注意的是,某些 COBOL 应用程序依赖于子系统或其他应用程序,可能无法使用某些语言元素。这种依赖关系和语言元素限制约束了 COBOL 程序。通过绕过这些限制,您就可以主动获得在多线程上运行程序的好处。

在本文中,我将介绍一些解决步骤,以避免被动处理 COBOL 多线程的限制:

  1. 小心那些不希望使用的语言元素
  2. 了解语言元素的范围(scope)
  3. 为编译做好准备
  4. 编译、链接并运行程序

第一步:小心那些不希望使用的语言元素

在多线程环境中编写 COBOL 程序时,选择合适的链接语句和语言元素,包括语句、专用寄存器和构成 COBOL 程序逻辑的语句。小心那些无法用于多线程的语言元素。如果使用 THREAD 编译器选项编译包含不恰当元素的程序,则会将这些元素标记为错误。

下面的表 1 显示了不受 THREAD 编译器选项支持、应当避免的语言元素。在 Standard COBOL 85 中,这些语言元素被划分到已作废的类别中,并且不属于 Standard COBOL 2002 的一部分。

表 1. 不受 THREAD 编译器选项支持的语言元素
语言元素类型
ALTER语句
DEBUG-ITEM专用寄存器
GO TO without procedure name语句
INITIAL phrase in PROGRAM-ID子句
RERUN子句
Segmentation module模块
STOP literal语句
STOP RUN语句
USE FOR DEBUGGING声明

当找到这些不需要的语言元素后,可能需要用具有类似功能的元素替换它们,并且 THREAD 编译器选项支持这些替换的元素。对于某些替换,需要修改程序逻辑或链接语句。

下面几个例子演示了如何处理不受支持的语言元素:

使用 EVALUATE 语句替换 ALTER 语句。已被废弃的 ALTER 语句提供了与 EVALUATE 相同的功能。然而,EVALUATE 提供了更多、更好的选项,鼓励使用结构化编程。ALTER 语句修改了 GO TO 语句中指定的转移点 (transfer point)。EVALUATE 语句的功能远远不止这一点,它还可以充当某些条件的一系列 IF 条件语句,并为每个条件指定一个不同的操作。您可以使用 EVALUATE 构建一个 case 结构。

如果发现 GO TO 语句缺少对某个程序的引用,那么该程序将无法正确进行编译。相反,它会使用 PERFORM procedure-name-1 THRU procedure-name-2。如果试图将 GO TO 语句与程序名一起使用,那么可以考虑将 EVALUATE 语句作为一个替换选项。

STOP RUN 语句关闭了运行单元内的任意程序中定义的所有文件。在线程环境中,没有 COBOL 函数可以有效地执行 STOP RUN 功能。如果需要使用这种行为,可以考虑从 COBOL 程序调用 C exit 函数,并在运行时终止退出后使用 _twzCOBOLTerm。

可以考虑将 GOBACK 或 EXIT PROGRAM 作为另一种终止程序运行的方法。GOBACK 语句指定了所调用的程序或方法的逻辑结束部分。这将使您返回到程序的调用方。当从线程中的第一个程序(并不一定总是主程序)中使用 GOBACK 时,该程序将终止。像使用 GOBACK 那样使用 EXIT PROGRAM,唯一例外的地方是它对主程序无效。

当您未对 COBOL 环境进行预初始化就执行存储清除 (cleanup) 时,并且 COBOL 运行库确定运行单元中不存在活跃的 COBOL 程序,那么将在线程的第一个程序中使用 GOBACK 执行 COBOL 流程来终止运行单元(包括关闭所有打开的 COBOL 文件)。如果运行单元内的所有 COBOL 程序都通过 GOBACK 或 EXIT PROGRAM 返回给其调用者,那么就可以确定这一点。

不要使用 CANCEL 语句替换 EXIT PROGRAM 语句。如果 CANCEL 语句指定了一个程序,并且该程序对于任意线程都是活跃的,那么执行将失败。指定的程序必须处于非活跃状态。

使用 -g 编译器选项替代 USE FOR DEBUGGING,提示编译器为源代码生成调试信息。

第二步:在两个范围(scope)内使用语言元素

由于您的 COBOL 程序在进程中可以作为单独的线程运行,因此可以在两个不同的范围内解释语言元素:运行单元范围或程序调用实例范围。这两种范围对于决定引用项目的位置以及项目的存储周期的长短非常重要。

在一个多线程环境中,COBOL 运行单元是进程的一部分,包括实际已经执行 COBOL 程序的线程。当 COBOL 运行单元处于运行状态时,语言元素将保持不变,并且可用于同一线程中的其他程序。这种情况将一直持续下去,直到任何线程的执行堆栈中再也没有活动的 COBOL 程序。例如,一个已调用的 COBOL 程序包含 GOBACK 语句(一个语言元素)并向某个 C 程序返回控制权。在运行单元的范围内,COBOL 程序可以调用非 COBOL 程序,反之亦然。

在线程内,控制权在不同 COBOL 和非 COBOL 程序之间转移。例如,一个 COBOL 程序可以调用另一个 COBOL 程序或 C 程序。每个被单独调用的程序就是一个程序调用实例。这些特定程序的实例可以存在于给定进程的多个线程中。语言元素则仅存在于特定的程序调用中。

表 2 总结了可以应用于线程的各种 COBOL 语言元素的范围。它们包括专用寄存器、语句和 DATA DIVISION 部分。

表 2. COBOL 语言元素的范围
语言元素引用自生命周期
ADDRESS-OF 专用寄存器与关联记录相同程序调用实例
LENGTH OF 专用寄存器与关联的标识符相同与关联的标识符相同
LINAGE-COUNTER 专用寄存器运行单元运行单元
LINKAGE-SECTION 数据运行单元基于底层数据的范围
LOCAL-STORAGE 数据线程程序调用实例
RETURN-CODE运行单元程序调用实例
SORT-CONTROL、SORT-CORE-SIZE、SORT-RETURN、TALLY 专用寄存器运行单元程序调用实例
WHEN-COMPILED 专用寄存器运行单元运行单元
WORKING-STORAGE 数据运行单元运行单元

专用寄存器

专用寄存器是一些保留字,用于指定编译器生成的存储区域。它们的主要用途是存储通过特定 COBOL 特性产生的信息。每一个这种存储区域都有一个固定的名称,并且不能在程序内部定义它。

确保为专用寄存器提供了足够的存储空间。在运行程序时,经常清理将要分配给多个线程的存储空间。

对于使用 THREAD 选项编译的程序(以及在 PROGRAM-ID 段落中包含 RECURSIVE 属性的程序),以下专用寄存器的存储将根据每个调用进行分配:

  • ADDRESS-OF
  • RETURN-CODE
  • SORT-CONTROL
  • SORT-CORE-SIZE
  • SORT-FILE-SIZE
  • SORT-MESSAGE
  • SORT-MODE-SIZE
  • SORT-RETURN
  • TALLY

除了 ADDRESS-OF 和 LINAGE-COUNTER 专用寄存器外,其他专用寄存器都可以从运行单元中引用。它们也可以作为运行单元跨越程序的生命周期,并针对每个程序或方法条目重设初始值。对于某个程序被取消后的第一个调用,或对于某个方法调用,编译器会初始化这些专用寄存器的字段,将它们作为初始值。ADDRESS-OF 专用寄存器中的值集合将仅在特定程序或方法调用期间存在。

将为每个包含 LINAGE 子句的 FD 条目生成一个 LINAGE-COUNTER 专用寄存器。当生成多个专用寄存器时,必须用相关联的文件名指定对 LINAGE-COUNTER 的每个引用。

LINAGE-COUNTER 中的值在任何给定时间都表示设备在当前页面中的行号。可以在程序划分语句中引用 LINAGE-COUNTER;但不能用这些语句修改它。

存储数据

在 DATA DIVISION 中,FILE SECTION 中的所有文件都静态分配了存储空间,并且该空间将一直保留到运行单元结束。数据项的分配方式和初始化方式是各不相同的,这取决于这些数据项是在 WORKING-STORAGE SECTION 中还是在 LOCAL-STORAGE SECTION 中。

当调用某个程序后,就会分配与该程序相关联的 WORKING-STORAGE。含有 VALUE 子句的任意数据项将在此时被初始化为一个适当的值。在运行单元期间,WORKING-STORAGE 项将一直保持最后一次使用时的状态。

每次调用程序时,LOCAL-STORAGE SECTION 中定义的所有数据都将分配存储空间,并在程序结束后取消该分配。如果为一个 LOCAL-STORAGE 项指定了一个 VALUE 子句,那么该项在每次调用时都将被初始化为此值。如果没有指定 VALUE 子句,则表示没有定义该项的初始值。LINKAGE SECTION 描述了来自另一个程序的数据。

第三步:为编译做好准备

要在多个线程中运行 COBOL 程序,必须在应用程序中使用 THREAD 编译器选项对所有 COBOL 程序进行编译。在同一个应用程序中,不能将使用 THREAD 编译器选项编译的程序与使用默认的 NOTHREAD 编译器选项编译的程序混合在一起。

要准备好编译带有多个线程的 COBOL 程序,您需要:

  • 清理存储
  • 避免 CICS 环境
  • 采用递归调用
  • 使链接数据可用

清理存储

如果您的程序初始化了多个 COBOL 线程,不要认为 COBOL 程序(例如,您的 C 程序调用 COBOL 程序执行数据输入和输出)会清理它们的环境,比如释放不再使用的存储空间。

要让您的应用程序控制 COBOL 清理操作,需要预先初始化 COBOL 环境。可以通过使用程序的 COBOL 预先初始化界面实现这一点。在关闭文件后,您可以为将要分配给多个线程的存储腾出空间。

避免使用 CICS 环境

确保您将要在其中编译程序的环境不是 CICS 环境,因为无法在 CICS 环境中运行多线程应用程序。在 CICS 环境中,您可以在单线程中运行经过 THREAD 选项编译的 COBOL 程序,并且它是不包含多线程或 PL/I 任务的应用程序的一部分。

采用递归调用

要执行递归调用,必须在以递归方式调用的程序的 PROGRAM-ID 段落中编写 RECURSIVE 子句(或属性),或指定 THREAD 编译器选项。由于必须在多线程应用程序中将程序编写为递归方式,因此无法编写嵌套程序。您必须只对编译单元的最外层程序指定 RECURSIVE 子句。

使链接数据可用

如果程序包含 RECURSIVE 属性,或使用 THREAD 编译器选项编译,那么后续的程序调用将无法访问 LINKAGE SECTION 中定义的数据。要检索 LINKAGE SECTION 中的记录,则需要向程序传递一个参数,并在该程序的 USING 部分的相应位置上指定该记录。

第四步:编译、链接和运行程序

如果对多线程执行还编写了 C 程序和支持语言环境的汇编器程序,那么可以在同一个运行单元中将您的多线程 COBOL 程序与这些程序组合在一起。

多线程示例是展示如何使用命令编译、链接和执行程序的最佳方法之一。下面的表 3 列出了三个程序例子:一个 C 语言编译的主程序和两个 COBOL 程序。

表 3. 将要编译和运行的程序
程序名描述
thrcob.c 一个 C 程序,创建了两个 COBOL 线程,等待线程完成并退出
subd.cbl 一个 COBOL 程序,由 thrcob.c 创建的线程运行
subd.cbl 另一个 COBOL 程序,由 thrcob.c 创建的线程运行

确保 C 程序具有合理的设计,否则可能会创建过多的线程(超过两个),这将占用其他任务的空间。确保 COBOL 程序不会包含嵌套程序。

在 AIX shell 提示中,它使用三个命令编译程序,一个命令生成一个可执行主程序并运行该程序。

在编译 COBOL 程序时,可以对需要 THREAD 编译器的非 CICS 应用程序使用 cob2_r 命令。使用 cob2_j 命令可以编译面向对象(OO)的客户端和类。该命令包含 THREAD 选项,将它用作默认的调用选项。不要使用 cob2 命令。在生成和运行可执行程序时,始终检查是否存在编译错误。

创建编译后的程序

下面的清单 1 显示了需要在 AIX shell 提示中输入的三行命令,可用它们编译一个 C 主程序和两个 COBOL 程序,并假设源代码没有错误。

清单 1. 样例编译命令
xlc_r -c thecob.c
cob2_r -c  -g -qTHREAD subd.cbl
cob2_r -c  -g -qTHREAD sube.cbl

显然,-c 选项表示编译程序,但这里没有将它们链接起来。用于 COBOL 程序的命令中的 -q 选项将 THREAD 编译器选项传递给编译器。-g 选项提示编译器为源代码生成调试信息。

运行可执行模块

完成程序编译后,下面的清单 2 显示了两行命令。第一个命令通过将程序链接在一起生成了一个可执行模块。第二个命令将运行该模块。

清单 2. 样例编译命令
cob2_r  -o thrcob thecob.o subd.o sube.o
thecob

-o 选项用于链接程序,它将 thrcob 指定为可执行模块,并通过将 thrcob.osubd.osube.o 链接在一起生成该模块。如果没有使用 -o 选项,那么可执行模块的名称默认为 thrcob.out。

结束语

要处理 COBOL 多线程的局限性,则需要提前进行计划,去掉不需要的语言元素,修改程序逻辑,以包括受 THREAD 编译器选项支持的语言元素。开发人员应当在处理语言元素、进行编译准备,以及编译、链接和执行程序时与编程团队进行沟通。

参考资料

学习

  • IBM COBOL for AIX Programming Guide Version 4.1 中了解更多有关多线程的内容。
  • IBM COBOL for AIX Language Reference Guide 中了解更多有关语言语法的内容。
  • AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。
  • AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。
  • AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。
  • AIX and UNIX 下载中心:在这里你可以下载到可以运行在 AIX 或者是 UNIX 系统上的 IBM 服务器软件以及工具,让您可以提前免费试用他们的强大功能。
  • IBM Systems Magazine for AIX 中文版:本杂志的内容更加关注于趋势和企业级架构应用方面的内容,同时对于新兴的技术、产品、应用方式等也有很深入的探讨。IBM Systems Magazine 的内容都是由十分资深的业内人士撰写的,包括 IBM 的合作伙伴、IBM 的主机工程师以及高级管理人员。所以,从这些内容中,您可以了解到更高层次的应用理念,让您在选择和应用 IBM 系统时有一个更好的认识。

获得产品和技术

  • 希望对 AIX version 4.1.0 尝试使用 COBOL?下载 60 天免费试用版
  • 免费使用 IBM 软件。下载试用版本,登录到在线试用版,通过沙盒环境使用产品,或通过云访问。有 100 多种 IBM 产品试用版可供选择。

讨论

  • 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=AIX and UNIX
ArticleID=752309
ArticleTitle=COBOL 在多线程编程中的局限性
publish-date=08152011