This is samples of Micro Focus support multi-thread programming.
Step 1: Check multi-thread run-time system
CBL_THREAD_SELF API can be used to check whether multi-thread run-time ?
$ cat CHECK.cbl IDENTIFICATION DIVISION. PROGRAM-ID. CHECK. ENVIRONMENT DIVISION. CONFIGURATION SECTION. SOURCE-COMPUTER. RM-COBOL. OBJECT-COMPUTER. RM-COBOL. DATA DIVISION. WORKING-STORAGE SECTION. PROCEDURE DIVISION. *> INITIALIZATION CODE EXECUTED WHILE IN *> SINGLE-THREADED MODE TO CHECK IF THE *> RUN-TIME SYSTEM SUPPORTS MULTI-THREADING *> OR THE CBL_THREAD_ ROUTINES. CALL 'CBL_THREAD_SELF' ON EXCEPTION DISPLAY "EXCEPTION WHEN CALL CBL_THREAD_SELF" END-CALL IF RETURN-CODE = 1008 *>1008 THREADING NOT SUPPORTED IN THIS RUN-TIME SYSTEM. *> A THREADED APPLICATION ATTEMPTED TO USE THE ROUTINES *L THROUGH A NON-THREADED RUN-TIME SYSTEM. DISPLAY "MULTI-THREADING RUN-TIME SYSTEM CHECK FAIL" ELSE DISPLAY "MULTI-THREADING RUN-TIME SYSTEM CHECK PASS" END-IF STOP RUN.
Check program execution result:
$ cobrun CHECK MULTI-THREADING RUN-TIME SYSTEM CHECK FAIL $ cobrun_t CHECK MULTI-THREADING RUN-TIME SYSTEM CHECK PASS
Step 2: Sample Program 1
The main thread will create 5 threads, and wait until all threads to quit; for each thread, it will just sleep a few seconds and then quit.
- To create a thread.
- To pass parameters to thread
- To access shared variable exclusively (using mutex)
$ cat SIMPLE1.cbl PROGRAM-ID. 'SAMPLE1'. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 78 THREAD-COUNT VALUE 5. 01 I1 PIC 9(2) COMP-5. 01 THREAD-RETURN USAGE POINTER. 01 SHARED-STORAGE OCCURS THREAD-COUNT TIMES. 03 THREAD-ID PIC 9(2) COMP-5. 03 THREAD-HANDLE USAGE POINTER. 03 THREAD-DATA. 05 THREAD-DATA1 PIC X(10). 05 THREAD-DATA2 PIC 9(8) COMP-5. 01 MUTEX USAGE MUTEX-POINTER. 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 LOCAL-SHARED-STORAGE. 03 LOCAL-THREAD-ID PIC 9(2) COMP-5. 03 LOCAL-THREAD-HANDLE USAGE POINTER. 03 LOCAL-THREAD-DATA. 05 LOCAL-THREAD-DATA1 PIC X(10). 05 LOCAL-THREAD-DATA2 PIC 9(8) COMP-5. PROCEDURE DIVISION. OPEN MUTEX. DISPLAY "MAIN THREAD: ENTRY". PERFORM VARYING I1 FROM 1 BY 1 UNTIL I1 > THREAD-COUNT MOVE I1 TO THREAD-ID(I1) MOVE I1 TO THREAD-DATA1(I1) MOVE I1 TO THREAD-DATA2(I1) CALL 'CBL_THREAD_CREATE' USING 'SUBTHREAD' BY REFERENCE SHARED-STORAGE(I1) BY VALUE 0 1 *> Flag to create non-detached 0 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 "MAIN THREAD: EXIT". STOP RUN. ENTRY "SUBTHREAD" USING LOCAL-SHARED-STORAGE. DISPLAY LOCAL-THREAD-ID " ENTRY". SET MUTEX TO ON. DISPLAY LOCAL-THREAD-ID " SLEEP " LOCAL-THREAD-ID " SECONDS". MULTIPLY 100 BY LOCAL-THREAD-ID 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 LOCAL-THREAD-ID " HANDLE: " LOCAL-THREAD-HANDLE. DISPLAY LOCAL-THREAD-ID " DATA1: " LOCAL-THREAD-DATA1. DISPLAY LOCAL-THREAD-ID " DATA2: " LOCAL-THREAD-DATA2. SET MUTEX TO OFF. DISPLAY LOCAL-THREAD-ID " EXIT". STOP RUN.
Find the execution result:
$ cobrun_t SIMPLE1 MAIN THREAD: ENTRY 00001 ENTRY 00001 SLEEP 00001 SECONDS 00002 ENTRY 00003 ENTRY 00004 ENTRY 00005 ENTRY 00001 HANDLE: 00000140210818000520 00001 DATA1: 01 00001 DATA2: 0000000001 00001 EXIT 00002 SLEEP 00002 SECONDS 00002 HANDLE: 00000140210818033448 00002 DATA1: 02 00002 DATA2: 0000000002 00003 SLEEP 00003 SECONDS 00002 EXIT 00003 HANDLE: 00000140210818034904 00003 DATA1: 03 00003 DATA2: 0000000003 00003 EXIT 00004 SLEEP 00004 SECONDS 00004 HANDLE: 00000140210818036360 00004 DATA1: 04 00004 DATA2: 0000000004 00004 EXIT 00005 SLEEP 00005 SECONDS 00005 HANDLE: 00000140210818037816 00005 DATA1: 05 00005 DATA2: 0000000005 00005 EXIT MAIN THREAD: EXIT
Step 2: Sample Program 2
Sample2 is a similar program, but using thread LOCAL-STORAGE
$ cat SIMPLE2.cbl PROGRAM-ID. "SAMPLE2". ENVIRONMENT DIVISION. WORKING-STORAGE SECTION. 78 THREAD-COUNT VALUE 5. 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-HANDLE USAGE POINTER. 03 THREAD-DATA. 05 THREAD-DATA1 PIC X(10). 05 THREAD-DATA2 PIC 9(8) COMP-5. THREAD-LOCAL-STORAGE SECTION. LINKAGE SECTION. PROCEDURE DIVISION. DISPLAY "MAIN THREAD: ENTRY". SET THREAD-ENTRY TO ENTRY "SUB-THREAD" PERFORM VARYING I1 FROM 1 BY 1 UNTIL I1 > THREAD-COUNT MOVE I1 TO THREAD-ID(I1) MOVE I1 TO THREAD-DATA1(I1) MOVE I1 TO THREAD-DATA2(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 "MAIN THREAD: END". STOP RUN. END PROGRAM "SAMPLE2". ************************************************************ * SUB-THREAD. * ************************************************************ PROGRAM-ID. "SUB-THREAD". WORKING-STORAGE SECTION. 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 SHARED-STORAGE. 03 THREAD-ID PIC 9(2) COMP-5. 03 THREAD-HANDLE USAGE POINTER. 03 REAL-DATA. 05 THREAD-DATA1 PIC X(10). 05 THREAD-DATA2 PIC 9(8) COMP-5. PROCEDURE DIVISION USING SHARED-STORAGE. THREAD-SECTION. DISPLAY THREAD-ID " ENTRY". DISPLAY THREAD-ID " SLEEP " THREAD-ID " SECONDS". MULTIPLY 100 BY THREAD-ID 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 THREAD-ID " THREAD-HANDLE: " THREAD-HANDLE. DISPLAY THREAD-ID " THREAD-DATA1: " THREAD-DATA1. DISPLAY THREAD-ID " THREAD-DATA2: " THREAD-DATA2. EXIT PROGRAM. END PROGRAM "SUB-THREAD".
In this mode, the program SUB-THREAD, which is defined in SIMPLE2.cbl source file, will be compiled into a separated output file, i.e., SUB-THREAD.gnt
$ ls -l -rw-r--r-- 1 xxxxxx xxxx 2972 Mon Day HH:MM SIMPLE2.cbl -rw-r--r-- 1 xxxxxx xxxx 3647 Mon Day HH:MM SIMPLE2.gnt -rw-r--r-- 1 xxxxxx xxxx 4293 Mon Day HH:MM SUB-THREAD.gnt
Find the execution result:
$ cobrun_t SIMPLE2 MAIN THREAD: ENTRY 00001 ENTRY 0000200004 ENTRY 00004 ENTRY 00002 SLEEP 00003 ENTRY 00003 SLEEP 00004 SECONDS SLEEP 00003 SECONDS 00001 SLEEP 0000100002 SECONDS SECONDS 00005 ENTRY 00005 SLEEP 00005 SECONDS 00001 THREAD-HANDLE: 00000140008484775400 00001 THREAD-DATA1: 01 00001 THREAD-DATA2: 0000000001 00002 THREAD-HANDLE: 00000140008484816120 00002 THREAD-DATA1: 02 00002 THREAD-DATA2: 0000000002 00003 THREAD-HANDLE: 00000140008484817288 00003 THREAD-DATA1: 03 00003 THREAD-DATA2: 0000000003 00004 THREAD-HANDLE: 00000140008484818456 00004 THREAD-DATA1: 04 00004 THREAD-DATA2: 0000000004 00005 THREAD-HANDLE: 00000140008484819624 00005 THREAD-DATA1: 05 00005 THREAD-DATA2: 0000000005 MAIN THREAD: END