python3多线程----锁机制

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Version: python 3.6.3
# Tools: Pycharm 2017.3.3

__date__ = '2018/7/20 9:49'
__author__ = 'cdl'

import time
import threading

"""线程中的锁机制"""

"""
有两个线程A和B,A和B里的程序都加了同一个锁对象,当线程A率先执行到lock.acquire()(拿到全局唯一的锁后).
线程B只能等到线程A释放锁lock.release()后(归还锁)才能运行lock.acquire()(拿到全局唯一的锁)并执行后面的代码
"""
# 使用锁
lock = threading.Lock()  # 生成锁对象,全局唯一
lock.acquire()  # 获取锁。未获取到的线程会阻塞程序,直到获取到锁才会往下执行
lock.release()  #  释放锁,归回锁,其他线程可以拿去用了
# 注:lock.acquire() 和 lock.release()必须成对出现。否则就有可能造成死锁

# 为了避免出现死锁情况,推荐使用上下文管理器来加锁
lock = threading.Lock()
with lock:        # with语句会在这个代码块执行前自动获取锁,在执行结束后自动释放锁
    # 这里写自己的代码
    pass
# 使用锁的意义? -----------加锁是为了对锁内资源(变量)进行锁定,避免其他线程篡改已被锁定的资源,以达到我们预期的效果。
# 对比不用锁的线程
# def job1():
#     global n
#     for i in range(10):
#         n += 1
#         print('job1', n)
# def job2():
#     global n
#     for i in range(20):
#         n += 10
#         print('job2', n)
#
# n = 0
# threading_01 = threading.Thread(target=job1)
# threading_02 = threading.Thread(target=job2)
# threading_01.start()
# threading_02.start()
# 加锁之后进行对比
def job1():
    global n, lock
    lock.acquire()  # 获取锁
    for i in range(10):
        n += 1
        print('job1', n)
    lock.release()

def job2():
    global n, lock
    lock.acquire()  # 获取锁
    for i in range(10):
        n += 10
        print('job2', n)
    lock.release()
n = 0
lock = threading.Lock()  # 生成锁对象,全局唯一
threading_01 = threading.Thread(target=job1)
threading_02 = threading.Thread(target=job2)
threading_01.start()
threading_02.start()
# 有时候在同一个线程中,我们可能会多次请求同一资源(就是,获取同一锁钥匙),俗称锁嵌套
def main():
    n = 0
    lock = threading.Lock()
    with lock:
        for i in range(10):
            n += 1
            with lock:  # 第二次获取锁时,发现锁已经被同一线程的人拿走了。自己也就理所当然,拿不到锁,程序就卡住了。
                print(n)

t1 = threading.Thread(target=main)
t1.start()
# 可重入锁RLock,专门来处理这个问题
def num():
    n = 0
    # 生成可重入锁对象
    lock = threading.RLock()
    with lock:
        for i in range(10):
            n += 1
            with lock:
                print(n)

t1 = threading.Thread(target=num)
t1.start()
# 防止死锁的加锁机制
"""
出现情况:
同一线程,嵌套获取同把锁,造成死锁
多个线程,不按顺序同时获取多个锁。造成死锁
具体解释:
线程1,嵌套获取A,B两个锁,线程2,嵌套获取B,A两个锁。 
由于两个线程是交替执行的,是有机会遇到线程1获取到锁A,而未获取到锁B,在同一时刻,线程2获取到锁B,而未获取到锁A。
由于锁B已经被线程2获取了,所以线程1就卡在了获取锁B处,由于是嵌套锁,线程1未获取并释放B,是不能释放锁A的。
这是导致线程2也获取不到锁A,也卡住了。两个线程,各执一锁,各不让步,造成死锁。
"""
import threading
from contextlib import contextmanager

# Thread-local state to stored information on locks already acquired
_local = threading.local()

@contextmanager
def acquire(*locks):
    # Sort locks by object identifier
    locks = sorted(locks, key=lambda x: id(x))

    # Make sure lock order of previously acquired locks is not violated
    acquired = getattr(_local,'acquired',[])
    if acquired and max(id(lock) for lock in acquired) >= id(locks[0]):
        raise RuntimeError('Lock Order Violation')

    # Acquire all of the locks
    acquired.extend(locks)
    _local.acquired = acquired
    try:
        for lock in locks:
            lock.acquire()
        yield
    finally:
        # Release locks in reverse order of acquisition
        for lock in reversed(locks):
            lock.release()
        del acquired[-len(locks):]


x_lock = threading.Lock()
y_lock = threading.Lock()
def thread_1():
    while True:
        with acquire(x_lock):
            with acquire(y_lock):
                print('Thread-1')

def thread_2():
    while True:
        with acquire(y_lock):
            with acquire(x_lock):
                print('Thread-2')
t1 = threading.Thread(target=thread_1)
t1.daemon = True
t1.start()
t2 = threading.Thread(target=thread_2)
t2.daemon = True
t2.start()

猜你喜欢

转载自blog.csdn.net/cdlwhm1217096231/article/details/81139521