Threads created with CBL_THREAD_CREATE can be canceled with the CBL_THREAD_KILL routine. You cannot use CBL_THREAD_KILL to kill threads created in other ways. This call causes immediate, abnormal termination of a COBOL thread but, in general, it should not be used as part of general application thread control. The main reason for this is that some user and system synchronization resources will not be properly unlocked and/or freed when the thread terminates. This can affect the synchronization within the user application and the run-time system, which can cause serious problems with the application.
CBL_THREAD_KILL can reasonably be used within a critical error handler in the main thread. In this error handler, thread handles can be acquired by way of the CBL_THREAD_LIST_n routines, all threads can be canceled and the application can then exit via STOP RUN. This is less dangerous than the random use of CBL_THREAD_KILL as it minimizes the chance of needing a locked synchronization primitive but there is still a possibility of file corruption or deadlock during run-unit termination.
In any case, most applications should avoid using CBL_THREAD_KILL. This can be achieved by creating thread identification data (through the CBL_THREAD_IDDATA_ALLOC routine) that has a terminate flag in it. That data can then be polled in each thread at a level where no locks are held. If the terminate flag is set, then the polling thread can exit gracefully.
Example - Creating Thread Identification Data and Terminate Flags
******************** MAINPROG.CBL ******************** identification division. program-id. mainprog. Data Division. Local-Storage Section. 01 ret-ptr usage pointer. 01 iddata-ptr usage pointer. 01 sub-iddata-ptr usage pointer. 01 sub-handle usage thread-pointer. Linkage Section. 01 iddata-record. 05 iddata-name pic x(20). 05 iddata-term pic x comp-x value 0. Procedure Division. * Establish identification data - don't provide * initialization data when it is allocated, instead * initialize it after the pointer is retrieved. call 'CBL_THREAD_IDDATA_ALLOC' using by value zero length of iddata-record call 'CBL_THREAD_IDDATA_GET' using iddata-ptr omitted set address of iddata-record to iddata-ptr move 'main' to iddata-name * Create sub-thread * Starting point call 'CBL_THREAD_CREATE' using 'SUBPROG ' by value 0 *> No parameters 0 *> Optional - parameter size 0 *> Flag to create detached 0 *> Default priority 0 *> Default stack by reference sub-handle if return-code not = 0 display 'unable to create thread' stop run end-if * Wait until child creates its iddata and then flag * termination set sub-iddata-ptr to NULL perform until 1 = 0 call 'CBL_THREAD_IDDATA_GET' using sub-iddata-ptr by value sub-handle end-call if sub-iddata-ptr not = null exit perform end-if call 'CBL_THREAD_YIELD' end-perform set address of iddata-record to sub-iddata-ptr move "stop" to iddata-name move 1 to iddata-term * Wait till the child exits wait for sub-handle display 'All synchronization is complete on ' & 'RTS termination' stop run. end program mainprog. *************** SUBPROG.CBL ******************************** identification division. program-id. subprog. Data Division. Working-Storage Section. 01 sub-iddata. 05 sub-name pic x(20) value 'sub'. 05 sub-term pic x comp-x value 0. Local-Storage Section. 01 iddata-ptr usage pointer. 01 thread-handle usage pointer. 01 thread-state pic x(4) comp-x. 01 parent-handle usage pointer. Linkage Section. 01 iddata-record. 05 iddata-name pic x(20). 05 iddata-term pic x comp-x value 0. Procedure Division. * Establish identification data - provide initialization data call 'CBL_THREAD_IDDATA_ALLOC' using sub-iddata by value length of sub-iddata * Find our parent thread and resume him * call 'CBL_THREAD_LIST_START' using thread-handle thread-state iddata-ptr set parent-handle to NULL perform until thread-handle = null or return-code not = 0 if iddata-ptr not = null set address of iddata-record to iddata-ptr if iddata-name = 'main' set parent-handle to thread-handle exit perform end-if end-if call 'CBL_THREAD_LIST_NEXT' using thread-handle thread-state iddata-ptr end-perform call 'CBL_THREAD_LIST_END' if parent-handle = NULL display 'synchronization error' stop run end-if call 'CBL_THREAD_IDDATA_GET' using iddata-ptr omitted set address of iddata-record to iddata-ptr perform until iddata-term = 1 call 'CBL_THREAD_YIELD' end-perform exit program. end program subprog.
This rather lengthy example doesn't actually do anything but establish handshaking for thread and application termination. Before going into any discussion on it, it is worth noting that this kind of handshaking could have been accomplished more easily by passing the main thread's handle into the child as a parameter. This would have avoided the need to rely on identification data or to step through the thread list.
Consider the following points about the example application:
The method you use in your application depends on what level of contention you expect on identification data.
If a thread uses the CBL_THREAD_LIST routine:
For this reason you should:
These restrictions are removed only after stepping is terminated by a call to CBL_THREAD_LIST_END.