LKE Exercises

When using M Locks, you must use a well designed and defined locking protocol. Your locking protocol must specify guidelines for acquiring LOCKs, selecting and using timeout, releasing M Locks, defining a lock strategy according the given situation, identifying potential deadlock situations, and providing ways to avoid or recover from them. This section contains two exercises. The first exercise reinforces the concepts of GT.M LOCKs previously explained in this chapter. The second exercise describes a deadlock situation and demonstrates how one can use LKE to identify and resolve it.

Exercise 1: Preventing concurrent updates using M Locks

Consider a situation when two users (John and Tom) have to exclusively update a global variable ^ABC.

[Note] Note

Transaction Processing may offer a more efficient and more easily managed solution to the issue of potentially conflicting updates. For more information, see General Language Features of M chapter of the GT.M Programmer's Guide.

At the GT.M prompt of John, execute the following commands:

GTM>lock +^ABC

This command places a GT.M LOCK on "^ABC " (not the global variable^ABC). Note: LOCKs without the +/- always release all LOCKs held by the process, so they implicitly avoid dead locks. With LOCK +, a protocol must accumulate LOCKs in the same order (to avoid deadlocks).

Then execute the following command to display the status of the LOCK database.

GTM>zsystem "lke show -all"

This command produces an output like the following:

DEFAULT ^ABC Owned by PID= 3657 which is an existing
process

Now, without releasing lock^ABC, execute the following commands at the GT.M prompt of Tom.

GTM>lock +^ABC

This command wait for the lock on resource "^ABC " to be released. Note that that the LOCK command does not block global variable ^ABC in any way. This command queues the request for locking resource "^ABC" in the LOCK database. Note that you can still modify the value of global variable ^ABC even if it is locked by John.

Now, at the GT.M prompt of John, execute the following command:

GTM>zsystem "LKE -show -all -wait"

This command produces an output like the following:

DEFAULT ^ABC Owned by PID= 3657 which is an existing process 
Request PID= 3685 which is an existing process

This output shows that the process belonging to John with PID 3657 currently owns the lock for global variable ^ABC and PID of Tom has requested the ownership of that lock. You can use this mechanism to create an application logic that adhere to your concurrent access protocols.

Exercise 2: Rectifying a deadlock situation

Now, consider another situation when both these users (John and Tom) have to update two text files. While an update is in progress, a GT.M LOCK should prevent the other user from LOCKing that file. In some cases, a deadlock occurs when both users cannot move forward because they do not release their current LOCKs before adding additional LOCKs.

A deadlock situation can occur in the following situation:

John           Tom 
LOCK +file_1   LOCK +file_2 
LOCK +file_2   LOCK +file_1

Here both the users are deadlocked and neither can move forward. Note that a deadlock situation does not actually block the underlying resource.

Let us now create this situation.

At the GT.M prompt of John, execute the following commands:

GTM>set file1="file_1.txt"
GTM>lock +file1
GTM>open file1:APPEND 
GTM>use file1 
GTM>write "John",!
GTM>close file1

Note that John has not released the LOCK on resource "file1".

At the GT.M prompt of Tom, execute the following commands:

GTM> set file2="file_2.txt" 
GTM> lock +file2
GTM> open file2:APPEND 
GTM> use file2 
GTM>write "Tom",!
GTM>close file2

Note that Tom has not released the LOCK on resource "file2".

Now, at the GT.M prompt of John, execute the following commands.

GTM>set file2="file_2.txt" 
GTM>lock +file2

The latter command attempts to acquire a lock on resource file2 that is already locked by Tom. Therefore, this results in a deadlock situation. Repeat the same process for Tom and attempt to lock resource file1.

Execute the following command at LKE prompt to view this deadlock situation.

LKE>show -all -wait 
file1 Owned by PID= 2080 which is an existing process 
Request PID= 2089 which is an existing process 
file2 Owned by PID= 2089 which is an existing process 
Request PID=2080 which is an existing process

This shows a deadlock situation where neither user can proceed forward because it is waiting for the other user to release the lock. You can resolve this situation by clearing the locks using the LKE CLEAR -PID command.

[Caution] Caution

Avoid using the LKE CLEAR command to clear a deadlock in a production environment as it may lead to unpredictable application behavior. Always use the MUPIP STOP command to clear a deadlock situation in your production environment. However, in a debugging environment, you can use LKE to debug LOCKs, analyze the status of the LOCK database and even experiment with LKE CLEAR.