Open In App

# Python | Locking without Deadlocks

This article focuses on dealing with how to get more than one lock at a time if a multithread program is given along with avoiding the deadlocks.

Multithread programs – Due to the threads that keep on attempting to get multiple locks at once, these are very much prone to deadlocks. Understanding it with an example – a lock is already been acquired by a thread and then a second lock is attempted by the block then in that case, the program can freeze as the thread can potentially block the progress of other threads.

Solution:

• Enforcement of ordering rule
• Assigning each lock in a unique manner to the program.
• Only allowing multiple locks to be acquired in ascending order.

Code #1: Implementing the solution using a context manager.

## Python3

 `# importing libraries``import` `threading``from` `contextlib ``import` `contextmanager` `# threading to stored information``_local ``=` `threading.local()`  `@contextmanager``def` `acquire(``*``lock_state_state):` `    ``# Object identifier to sort the lock``    ``lock_state_state ``=` `sorted``(lock_state_state, key``=``lambda` `a: ``id``(a))` `    ``# checking the validity of previous locks``    ``acquired ``=` `getattr``(_local, ``'acquired'``, [])``    ``if` `acquired ``and` `max``(``id``(lock_state) ``for``                        ``lock_state ``in` `acquired) >``=` `id``(lock_state_state[``0``]):``        ``raise` `RuntimeError(``'lock_state Order Violation'``)` `    ``# Collecting all the lock state.``    ``acquired.extend(lock_state_state)``    ``_local.acquired ``=` `acquired` `    ``try``:``    ``for` `lock_state ``in` `lock_state_state:``        ``lock.acquire()``    ``yield``    ``finally``:` `        ``# locks are released in reverse order.``        ``for` `lock_state ``in` `reversed``(lock_state_state):``            ``lock_state.release()``        ``del` `acquired[``-``len``(lock_state_state):]`

Locks are acquired in the normal way using the context manager and for performing this task acquire() function is used as there was more than one lock as shown in the code below :

Code #2 :

## Python3

 `# threads``import` `threading` `# creating locks``lock_state_1 ``=` `threading.Lock()``lock_state_2 ``=` `threading.Lock()` `# using acquire as there are more than one lock`  `def` `thread_1():``    ``while` `True``:``        ``with acquire(lock_state_1, lock_state_2):``            ``print``(``'Thread-1'``)`  `def` `thread_2():``    ``while` `True``:``        ``with acquire(lock_state_2, lock_state_1):``            ``print``(``'Thread-2'``)`  `t1 ``=` `threading.Thread(target``=``thread_1)` `# daemon thread runs without blocking``# the main program from exiting``t1.daemon ``=` `True``t1.start()` `t2 ``=` `threading.Thread(target``=``thread_2)``t2.daemon ``=` `True``t2.start()`

• Even after the acquisition of the locks specification in a different order in each function – the program will run forever without deadlock.
• Sorting the locks plays an important role according to the object identifier as locks after being sorted get acquired in a consistent manner regardless of how the user might have provided them to acquire().
• If multiple threads are nested as shown in the code below, to solve a subtle problem with detection potential deadlock, thread-local storage is used.

Code #3 :

## Python3

 `# threads``import` `threading` `# creating locks``lock_state_1 ``=` `threading.Lock()``lock_state_2 ``=` `threading.Lock()`  `def` `thread_1():``    ``while` `True``:``        ``with acquire(lock_state_1):``            ``with acquire(lock_state_2):``                ``print``(``'Thread-1'``)`  `def` `thread_2():``    ``while` `True``:``        ``with acquire(lock_state_2):``            ``with acquire(lock_state_1):``                ``print``(``'Thread-2'``)`  `t1 ``=` `threading.Thread(target``=``thread_1)` `# daemon thread runs without blocking``# the main program from exiting``t1.daemon ``=` `True``t1.start()` `t2 ``=` `threading.Thread(target``=``thread_2)``t2.daemon ``=` `True``t2.start()`

On running this version of the program, one of the threads will crash with an exception such as :

```Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/HP/lib/python3.3/threading.py", line 639, in _bootstrap_inner
self.run()
File "/usr/HP/lib/python3.3/threading.py", line 596, in run
self._target(*self._args, **self._kwargs)
{"ft_lang_label":"__label__en","ft_lang_prob":0.8309116,"math_prob":0.4910649,"size":3887,"snap":"2023-40-2023-50","text_gpt3_token_len":1008,"char_repetition_ratio":0.18799897,"word_repetition_ratio":0.13167259,"special_character_ratio":0.25598148,"punctuation_ratio":0.147929,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9535342,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-09-27T04:31:17Z\",\"WARC-Record-ID\":\"<urn:uuid:43d59038-4054-4125-b74a-c0d56d2641b1>\",\"Content-Length\":\"253575\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:6604486b-df75-49eb-8cb5-52a8c544e1bd>\",\"WARC-Concurrent-To\":\"<urn:uuid:9ab70f51-1bb1-4034-85a1-bc36406a41f4>\",\"WARC-IP-Address\":\"23.62.230.103\",\"WARC-Target-URI\":\"https://www.geeksforgeeks.org/python-locking-without-deadlocks/?ref=rp\",\"WARC-Payload-Digest\":\"sha1:OFBNXQSDJLWSR4AHH6ZJ54VHAIBM4QQP\",\"WARC-Block-Digest\":\"sha1:F7B5K7NNCX7R53FU7KLKQBKPRYRBV6LE\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-40/CC-MAIN-2023-40_segments_1695233510259.52_warc_CC-MAIN-20230927035329-20230927065329-00727.warc.gz\"}"}