Intel® Fortran Compiler 17.0 Developer Guide and Reference
Statements: A LOCK statement causes a lock variable to become locked by an image. An UNLOCK statement causes the lock variable to become unlocked. They take the following forms:
LOCK (lock-var [, ACQUIRED_LOCK=log-var] [, STAT=stat-var] [, ERRMSG=err-var])
UNLOCK (lock-var [, STAT=stat-var] [, ERRMSG=err-var])
lock-var |
Is a scalar variable of type LOCK_TYPE. For more information, see intrinsic module ISO_FORTRAN_ENV. |
log-var |
Is a scalar logical variable. |
stat-var |
Is a scalar integer variable in which the status of the synchronization is stored. |
err-var |
Is a scalar default character variable in which explanatory text is stored if an error occurs. |
ACQUIRED_LOCK=, STAT=, and ERRMSG= can appear in any order, but only once in a LOCK statement.
STAT= and ERRMSG= can appear in either order, but only once in an UNLOCK statement.
A lock variable is unlocked if its value is equal to that of the structure constructor LOCK_TYPE ( ). If it has any other value, it is locked.
A lock variable is locked by an image if it was locked by execution of a LOCK statement on that image and has not been subsequently unlocked by execution of an UNLOCK statement on the same image.
When a LOCK statement is specified without an ACQUIRED_LOCK= specifier, it causes the lock variable to become locked by that image. If the lock variable is already locked by another image, that LOCK statement causes the lock variable to become defined after the other image causes the lock variable to become unlocked.
If the lock variable is unlocked, successful execution of a LOCK statement with an ACQUIRED LOCK= specifier causes the lock variable to become locked by that image and the log-var to become defined with the value TRUE. If the lock variable is already locked by a different image, successful execution of a LOCK statement with an ACQUIRED LOCK= specifier leaves the lock variable unchanged and causes the log-var to become defined with the value FALSE.
During the execution of the program, the value of a lock variable changes through a sequence of locked and unlocked states when LOCK and UNLOCK statements are executed. If a lock variable becomes unlocked by execution of an UNLOCK statement on image M and next becomes locked by execution of a LOCK statement on image T, the segments preceding the UNLOCK statement on image M precede the segments following the LOCK statement on image T. Execution of a LOCK statement that does not cause the lock variable to become locked does not affect segment ordering.
An error condition occurs in the following cases:
If the lock variable in a LOCK statement is already locked by the executing image
If the lock variable in an UNLOCK statement is not already locked by the executing image
If an error condition occurs during execution of a LOCK or UNLOCK statement, the value of the lock variable is not changed and the value of the ACQUIRED_LOCK variable, if any, is not changed.
The following example shows the use of LOCK and UNLOCK statements to manage a work queue:
USE, INTRINSIC :: ISO_FORTRAN_ENV
TYPE(Task) :: work_queue(50)[*] ! List of tasks on queue to perform
INTEGER :: work_queue_size[*]
TYPE(LOCK_TYPE) :: work_queue_lock[*] ! Lock to manage the work queue
TYPE(Task) :: current_task
INTEGER :: my_image
my_image = THIS_IMAGE()
DO
! Process the next task in the work queue
LOCK (work_queue_lock) ! Start of new segment A
! Segment A is ordered with respect to segment B
! executed by image my_image-1 below because of lock exclusion
IF (work_queue_size>0) THEN
! Get the next job from the queue
current_task = work_queue(work_queue_size)
work_queue_size = work_queue_size-1
END IF
UNLOCK (work_queue_lock) ! Segment ends
...
! Process the task
! Add a new task on the neighboring queue:
LOCK(work_queue_lock[my_image+1]) ! Starts segment B
! Segment B is ordered with respect to segment A
! executed by image my_image+1 above because of lock exclusion
IF (work_queue_size[my_image+1]<SIZE(work_queue)) THEN
work_queue_size[my_image+1] = work_queue_size[ti+1]+1
work_queue(work_queue_size[my_image+1])[my_image+1] = current_task
END IF
UNLOCK (work_queue_lock[my_image+1]) ! Ends segment B
END DO