Python Threading RLock (Reentrant): When and How to use them

Whenever we create a Thread Lock, the rule of mutual exclusion states that a lock can only be acquired by a single thread at a time. However, there is another special type of Lock called RLock in the Python threading module.

They are also known as “Reentrant” Locks, but I personally like to call them “Recursive Locks”. You’ll soon understand why.


How to use RLock in Python

As we mentioned earlier, regular Locks (created through the Lock Class) cannot be acquired multiple times under any circumstances.

With an RLock however, there is a special circumstance under which a Lock can be acquired again, or even many times by the same thread. If a lock created through RLock has been acquired once, then within the very same critical section the lock may be acquired again.

Note: The Critical section refers to the code in between the acquire() and release() function calls, where we access the shared resource.

RLock allows for such behavior by also including “Recursion depth” as a factor in determining whether a lock can be acquired or not. Basically nested pairs of acquire() and release() can be placed within the critical section.

Only the final (the outermost) release() will actually properly “release” the lock and allow it to be used by other threads.


RLock Example

Observe the below example carefully. You will notice that func_1 makes a function call to func_2 inside it’s critical section. func_2 then makes an attempt to acquire the same lock. And it succeeds immediately without having to wait! (you can verify this in the output).

This is because the “nested” lock is regarded as uncontested.

from threading import Thread, Lock, RLock
from time import sleep

lock = RLock()

def func_2(lock):
    print("Function# 2: Waiting for Lock")
    lock.acquire()

    print("Function# 2: Executing Code....")
    sleep(1)

    lock.release()
    print("Function# 2: Releases Lock")


def func_1(lock):
    print("Function# 1: Waiting for Lock")
    lock.acquire()

    # Enter the Critical Seciton
    print("Function# 1: Executing Code....")
    func_2(lock)

    lock.release()
    print("Function# 1: Releases Lock")


thread = Thread(target= func_1, args= (lock,))
thread.start()
thread.join()

As you can see from the output here, Function#2 began executing even before Function#1 released the lock.

Function# 1: Waiting for Lock
Function# 1: Executing Code....
Function# 2: Waiting for Lock  
Function# 2: Executing Code....
Function# 2: Releases Lock
Function# 1: Releases Lock

Another notable point here is that Function#1 is the last one to release the lock.


This marks the end of the Python Threading RLock Tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments