Micro Focus COBOL multi-thread solution


There are 4 solution to support multi-thread program; it's depend on customer's requirement which one can be used properly.(Details from MF document)


To launch a multi-thread program, please use 'cobrun_t' instead of 'cobrun'.

Three Kinds of Storage

  • Working-Storage SectionData item in Working-Storage Section are global shared, among all threads.
  • Local-Storage SectionLocal-Storage Section works as function local variable;  for every recursion of the program a new instance of this data is allocated on the stack.
  • Thread-Local-Storage SectionThread-Local-Storage Section, Thread-local data can be viewed as a thread-specific Working-Storage data item.

Solution 1: Using Compiler Directive SERIAL

Compile your COBOL programs with the SERIAL directive.

SERIAL causes the COBOL run-time system to serialize access to your COBOL code between different threads. Only one thread can access your program at a time. This is the safest option, although it has potentially the highest overhead for execution speed. It is suitable when the COBOL program is providing access to a shared resource (for example, a printer), or when the COBOL program called from Java is in turn calling other COBOL programs which have not been enabled for multi-threading. 


For example:

MAINPROG will create 2 threads SUBPROG, and each thread will call a SUBSLEEP. Since SUBSLEEP will be called at the same time by two threads SUBPROG.


  • If SERIAL compiler directive is set when compile SUBSLEEP program
$ make
cob -ug MAINPROG.cbl -C "list(MAINPROG.lst)" -C XREF -C SETTINGS
cob -ug SUBPROG.cbl -C "list(SUBPROG.lst)" -C XREF -C SETTINGS
cob -ug SUBSLEEP.cbl -C "list(SUBSLEEP.lst)" -C XREF -C SETTINGS -C SERIAL

$ cobrun_t MAINPROG
SUBSLEEP ENTRY, WSS-VAR=00
SUBSLEEP EXIT,  WSS-VAR=01
SUBSLEEP ENTRY, WSS-VAR=01
SUBSLEEP EXIT,  WSS-VAR=02

We can find that only one SUBSLEEP can be run at a time. The second will not come in until the first has quit.


  • If NO SERIAL compiler directive is set when compile SUBSLEEP program
$ make
cob -ug MAINPROG.cbl -C "list(MAINPROG.lst)" -C XREF -C SETTINGS
cob -ug SUBPROG.cbl -C "list(SUBPROG.lst)" -C XREF -C SETTINGS
cob -ug SUBSLEEP.cbl -C "list(SUBSLEEP.lst)" -C XREF -C SETTINGS

$ cobrun_t MAINPROG
SUBSLEEP ENTRY, WSS-VAR=00
SUBSLEEP ENTRY, WSS-VAR=01
SUBSLEEP EXIT,  WSS-VAR=02
SUBSLEEP EXIT,  WSS-VAR=02

We can find both SUBSLEEP can be entry at the same time.


Notice: The WSS is global, the setting on first coming will affect the later value.


Solution 2: Making per-thread Working-Storage Section

Compile your COBOL programs with the REENTRANT"2" directive.

REENTRANT"2" causes the COBOL run-time system to allocate separate user data and FD file areas to each different thread. This prevents any conflicts or data corruption within the program. But REENTRANT"2" can't guarantee thread-safety if it calls other non-threaded programs, or accesses other shared resources - in these sorts of cases, SERIAL is a safer option. The REENTRANT"2" directive can provide better performance than SERIAL as one thread is not kept waiting for the next thread to finish.

(REENTRANT"1" is default setting)


In other words, REENTRANT"2" make WSS per-thread, so there is no shared data between different threads.

$ make
cob -ug MAINPROG.cbl -C "list(MAINPROG.lst)" -C XREF -C SETTINGS
cob -ug SUBPROG.cbl -C "list(SUBPROG.lst)" -C XREF -C SETTINGS
cob -ug SUBSLEEP.cbl -C "list(SUBSLEEP.lst)" -C XREF -C SETTINGS -C REENTRANT=2

$ cobrun_t MAINPROG
SUBSLEEP ENTRY, WSS-VAR=00
SUBSLEEP ENTRY, WSS-VAR=00
SUBSLEEP EXIT,  WSS-VAR=01
SUBSLEEP EXIT,  WSS-VAR=02


Solution 3: Using Thread-Local-Storage Section

Use thread-local storage in your COBOL programs instead of working storage.

Thread-local storage is allocated per thread, so there is no possibility of one thread corrupting the data used by another thread. This is fairly efficient, but might not always be an option with legacy code.


In fact, Solution 2 is trying to make Working-Storage Section work as Thread-Local-Storage Section.


Solution 4: Using Synchronized Operation


Multi-thread your COBOL program using COBOL multi-threading syntax or run-time system calls.

This can be very efficient as you control which data is thread-local and which data is shared between threads. You could use this option in COBOL driver programs that sit between the Java run-time environment and your legacy COBOL programs. Your driver program would be responsible for controlling access to the legacy programs, and would need to use semaphores or some similar mechanism to prevent two threads from accessing the same code at the same time.


You can use MUTEX to access variable exclusively.

With this solution, Working-Storage Section are not allocated pre-thread, they are shared, so it's depend on synchronized strategy to make variable access exclusively when necessary.


Appendix: Program Sources

MAINPROG.cbl

       PROGRAM-ID. "MAINPROG". 
       ENVIRONMENT DIVISION. 

       WORKING-STORAGE SECTION. 
       78 THREAD-COUNT VALUE 2.
       01 I1    PIC 9(2) COMP-5.

       01 THREAD-ENTRY     USAGE PROCEDURE-POINTER.
       01 THREAD-RETURN    USAGE POINTER.

       01 SHARED-STORAGE OCCURS THREAD-COUNT TIMES.
          03 THREAD-ID          PIC 9(2) COMP-5.
          03 THREAD-DATA        PIC X(10).
          03 THREAD-HANDLE      USAGE POINTER.

       PROCEDURE DIVISION. 
*     *    DISPLAY "MAINPROG: ENTRY".
           SET THREAD-ENTRY    TO ENTRY "SUBPROG"

           PERFORM VARYING I1 FROM 1 BY 1 UNTIL I1 > THREAD-COUNT
               MOVE I1 TO THREAD-ID(I1)
               MOVE I1 TO THREAD-DATA(I1)

               CALL "CBL_THREAD_CREATE_P" USING
                    BY VALUE THREAD-ENTRY
                    BY REFERENCE SHARED-STORAGE(I1)
                    BY VALUE     0
*     *             BY VALUE     LENGTH OF SHARED-STORAGE(I1)
                    BY VALUE     1 
                    BY VALUE     0 
                    BY VALUE     0 
                    BY REFERENCE THREAD-HANDLE(I1)
               IF RETURN-CODE NOT = 0 
                   DISPLAY "FAIL: CANNOT CREATE THREAD" 
                   STOP RUN 
               END-IF 
           END-PERFORM 


           PERFORM VARYING I1 FROM 1 BY 1 UNTIL I1 > THREAD-COUNT
                CALL 'CBL_THREAD_WAIT'  USING
                                        BY VALUE THREAD-HANDLE(I1)
                                        BY REFERENCE THREAD-RETURN
           END-PERFORM.

      *    DISPLAY "MAINPROG EXIT".
           STOP RUN. 

       END PROGRAM "MAINPROG". 



SUBPROG.cbl

       PROGRAM-ID. "SUBPROG". 
       WORKING-STORAGE SECTION. 
       01 SLEEP-PARM.
          03 CALLER     PIC X(10).
          03 SECOND     PIC 9(2) COMP-5.
          03 TID        PIC 9(2) COMP-5.

       LOCAL-STORAGE SECTION.

       LINKAGE SECTION. 
       01 THREAD-PARM.
          03 THREAD-ID          PIC 9(2) COMP-5.
          03 THREAD-DATA        PIC X(10).
          03 THREAD-HANDLE      USAGE POINTER.

       PROCEDURE DIVISION USING THREAD-PARM. 
      *    DISPLAY "SUBPROG ENTRY".

           MOVE "SUBPROG" TO CALLER.
           MOVE 2 TO SECOND.
           MOVE THREAD-ID TO TID.
           CALL "SUBSLEEP" USING SLEEP-PARM.

      *    DISPLAY "SUBPROG EXIT".
           EXIT PROGRAM. 
       END PROGRAM "SUBPROG"



SUBSLEEP.cbl

       PROGRAM-ID. "SUBSLEEP". 
       WORKING-STORAGE SECTION. 
       01  WSS-VAR      PIC 9(02) VALUES 0.

       LOCAL-STORAGE SECTION.
       01 SLEEPTIME                 PIC 9(8).

       01 TIME-TODAY-1              PIC 9(8) VALUE 0.
       01 TIME-TODAY-2              PIC 9(8) VALUE 0.
       01 DELTATIME                 PIC 9(8) VALUE 0.

       LINKAGE SECTION. 
       01 SLEEP-PARM.
          03 CALLER     PIC X(10).
          03 SECOND     PIC 9(02) COMP-5.
          03 TID        PIC 9(2) COMP-5.

       PROCEDURE DIVISION USING SLEEP-PARM. 
       THREAD-SECTION. 
           DISPLAY "SUBSLEEP ENTRY, WSS-VAR=" WSS-VAR.
           MOVE TID TO WSS-VAR.

           MULTIPLY 100 BY SECOND GIVING SLEEPTIME.
           ACCEPT TIME-TODAY-1 FROM TIME.
           PERFORM UNTIL DELTATIME >= SLEEPTIME
            ACCEPT TIME-TODAY-2 FROM TIME
            COMPUTE DELTATIME = (TIME-TODAY-2 - TIME-TODAY-1)
           END-PERFORM.

           DISPLAY "SUBSLEEP EXIT,  WSS-VAR=" WSS-VAR.
 
           EXIT PROGRAM. 
       END PROGRAM "SUBSLEEP".


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值