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.