官术网_书友最值得收藏!

Example of deadlock handling

Let's look at a quick example in Python. Let's a take look at the Chapter04/example2.py file, as shown in the following code:

# Chapter04/example2.py

from threading import Lock

my_lock = Lock()

def get_data_from_file_v1(filename):
my_lock.acquire()

with open(filename, 'r') as f:
data.append(f.read())

my_lock.release()

data = []

try:
get_data_from_file('output2/sample0.txt')
except FileNotFoundError:
print('Encountered an exception...')

my_lock.acquire()
print('Lock can still be acquired.')

In this example, we have a get_data_from_file_v1()function that takes in the path to an external file, reads the data from it, and appends that data to a predeclared list called data. Inside this function, a lock object called my_lock, which is also predeclared prior to the function being called, is acquired and released as the parameter file is read before and after, respectively.

In the main program, we will try to call get_data_from_file_v1() on a nonexistent file, which is one of the most common errors in programming. At the end of the program, we also acquire the lock object again. The point is to see whether our programming could handle the error of reading a nonexistent file appropriately and gracefully with just the try...except block that we have.

After running the script, you will notice that our program will print out the error message specified in the try...except block, Encountered an exception..., which is expected, since the file could not be found. However, the program will also fail to execute the rest of the code; it will never get to the last line of code—print('Lock acquired.')—and will hang forever (or until you hit Ctrl + C to force-quit the program).

This is a deadlock situation, which, again, occurs when my_lock is acquired inside the get_data_from_file_v1() function, but since our program encountered an error before executing my_lock.release(), the lock was never released. This in turn caused the my_lock.acquire() line at the end of the program to hang, as the lock could not be acquired in any way. Our program hence could not reach its last line of code, print('Lock acquired.').

This problem, however, could be handled with a with statement easily and effortlessly. In the example2.py file, simply comment out the line calling get_data_from_file_v1() and uncomment the line calling get_data_from_file_v2(), and you will have the following:

# Chapter04/example2.py

from threading import Lock

my_lock = Lock()

def get_data_from_file_v2(filename):
with my_lock, open(filename, 'r') as f:
data.append(f.read())

data = []

try:
get_data_from_file_v2('output2/sample0.txt')
except:
print('Encountered an exception...')

my_lock.acquire()
print('Lock acquired.')

In the get_data_from_file_v2() function, we have the equivalent of a pair of nested with statements, as follows:

with my_lock:
with open(filename, 'r') as f:
data.append(f.read())

Since Lock objects are context managers, simply using with my_lock: would ensure that the lock object is acquired and released appropriately, even if an exception is encountered inside the block. After running the script, you will have the following output:

> python example2.py
Encountered an exception...
Lock acquired.

We can see that, this time, our program was able to acquire the lock and reach the end of the script gracefully and without errors.

主站蜘蛛池模板: 比如县| 永登县| 通州市| 洛南县| 长寿区| 丹寨县| 富宁县| 驻马店市| 缙云县| 长子县| 宜君县| 广东省| 榆社县| 都江堰市| 彝良县| 南澳县| 土默特左旗| 白水县| 仙游县| 镇远县| 崇礼县| 靖江市| 凯里市| 合作市| 闻喜县| 安远县| 凤庆县| 张家港市| 夹江县| 富蕴县| 梁山县| 会同县| 金沙县| 和顺县| 太仆寺旗| 潼南县| 剑川县| 富平县| 色达县| 远安县| 广水市|