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

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.

主站蜘蛛池模板: 澳门| 申扎县| 巴塘县| 乐昌市| 龙泉市| 云南省| 万载县| 桃源县| 桑植县| 珠海市| 桂平市| 连州市| 小金县| 玛沁县| 兰溪市| 毕节市| 谢通门县| 宁晋县| 滕州市| 清水县| 定安县| 安康市| 北碚区| 绵竹市| 新竹市| 锦州市| 安吉县| 新源县| 安平县| 望谟县| 平邑县| 麻阳| 天镇县| 北京市| 万盛区| 广德县| 华亭县| 康乐县| 广德县| 阜平县| 宁海县|