It is sometimes useful for a thread to distinguish itself from any other created threads in an application. For example, if two threads in a four thread application establish a producer-consumer relationship, it can be useful for the two cooperating threads to find out what each other's thread handles are. Once these handles are obtained, all synchronization can be done using only the CBL_THREAD_SUSPEND and CBL_THREAD_RESUME calls. If each thread in the application creates a name for itself (and the name relates to its functionality) and associates the name with its thread handle, then the cooperating threads can scan the thread name list and find each other's handle.
Another possible use for associating globally accessible data to each thread and its handle is to hold a termination flag, obviating the possible need to use CBL_THREAD_KILL. Each thread in the application can poll its termination flag to check for a termination request. The terminating thread can then make sure no locks are held and no synchronization actions are required before terminating normally.
Globally accessible data for a thread is associated with the thread handle by the CBL_THREAD_IDDATA_ALLOC routine executed within the thread. This data is retrieved by the CBL_THREAD_IDDATA_GET routine, if the thread handle is already known, or by the CBL_THREAD_LIST_n routines if the thread handle is not yet known.
Example - Associating Globally Accessible Data With a Thread Handle
The following example shows how to associate globally accessible data with the thread handle by using the CBL_THREAD_IDDATA_ALLOC call executed within the thread. The data is retrieved by the CBL_THREAD_IDDATA_GET call, if the thread handle is already known, or by the CBL_THREAD_LIST_n routines if the thread handle is not yet known.
*************** MAINPROG.CBL ************************ identification division. program-id. mainprog. Data Division. Local-Storage Section. 01 ret-wait 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 start 'SUBPROG ' identified by sub-handle * 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 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 1 to iddata-term * Wait until the child ends wait for sub-handle *> clear up thread's resources 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 example establishes handshaking for thread and application termination. Note that this kind of handshaking could have been accomplished more easily by passing the handle of the main thread 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 this example:
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_n routines:
For this reason you should:
These restrictions are removed only after list stepping is terminated by a call to CBL_THREAD_LIST_END.