"""
① 互斥锁:Lock,一次只能放行一个,可以通过 with 语句调用。
② 可重入锁:RLock,一次只能放行一个,可以通过 with 语句调用。
③ 条件锁:Condition,一次可以放行任意个,可以通过 with 语句调用。
④ 事件锁:Event,一次全部放行,不能通过 with 语句调用。
⑤ 信号量锁:semaphore,一次可以放行特定个,可以通过 with 语句调用。
Event是python中的事件锁,Event对象有一个信号标志,默认是False, 默认是阻塞的,需要使用Event.set()方法来设置为True,
可以将Event传入线程内,然后通过Event.wait()方法阻塞线程,实现线程同步,不过Event对象一次放行所有的进程;
Semaphore是python中的信号量锁,可以用来控制线程的并发数量;
"""
import threading
import time
DENG = {False: "红灯",
True: "绿灯"}
class Event_LOCK(object):
def __init__(self):
pass
def light(self, env):
is_lock = env.is_set()
print("当前时间是:{}, 红绿灯是:{}, 还有3S结束!".format(time.ctime(), DENG[is_lock]))
time.sleep(3)
if env.is_set:
print("绿灯放行!")
env.set()
def car(self, env, name):
print("当前时间是:{}, 车: {} 在等红灯!".format(time.ctime(), name))
env.wait()
print("当前时间是:{}, 车: {} 通过!".format(time.ctime(), name))
def run(self):
event = threading.Event()
thread_light = threading.Thread(target=self.light, args=(event, ))
thread_light.start()
for each in "ABCDE":
t1 = threading.Thread(target=self.car, args=(event, each))
t1.start()
# Demo 红绿灯 for threading.Event()对象
"""
事件锁 Event 并没有实现魔法方法 enter() 和 exit(),
所以不能通过 with 语句调用
Event对象的函数:
# 生成一个事件锁对象
eve = threading.Event()
# 将事件锁设置为红灯状态
eve.clear()
# 判断事件锁的状态
eve.is_set()
# 将当前线程设置’等待‘状态
eve.wait()
# 将事件锁设置为绿灯状态
eve.set()
"""
#Event_LOCK().run()
# Demo 上厕所 for threading.Semaphore
class Semaphore_LOCK(object):
def __init__(self):
pass
# Semaphore 里面也实现了 __enter__() 与 __exit__() 两个魔法方法,
# 所以也是可以通过 with 语句调用的
def deal(self, sem, name):
sem.acquire()
print("当前时间: {}, {}开始上厕所!".format(time.ctime(), name))
time.sleep(5)
sem.release()
print("当前时间: {}, {}出来了!,厕所空了!\n".format(time.ctime(), name))
def deal_use_with(self, sem, name):
with sem:
print("当前时间: {}, {}开始上厕所!".format(time.ctime(), name))
time.sleep(4)
print("当前时间: {}, {}出来了!,厕所空了!\n".format(time.ctime(), name))
def run(self):
# 只有四个坑,10个人上厕所,一次最多只能上4个人
sem = threading.Semaphore(4) #noqa
staffs = ["sam", 'jack', 'rose', 'dog', 'bey',
'tom', 'cat', 'black', 'shit', 'no']
for people in staffs:
#t1 = threading.Thread(target=self.deal, args=(sem, people))
t1 = threading.Thread(target=self.deal_use_with, args=(sem, people))
t1.start()
"""
Semaphore对象的函数:
# 生成一个信号量锁对象
sem = threading.Semaphore()
# 上锁,内置计数器减一
sem.acquire()
# 解锁,内置计数器加一
sem.release()
"""
#Semaphore_LOCK().run()
"""
Condition对象是python中的条件锁,内部使用LOCK和RLock锁实现,
所以具有阻塞的特性,再增加了暂停线程运行的功能,
可以用来实现同步复杂的线程间通信;
# 生成一个条件锁对象
cond = threading.Condition()
# 上锁
cond.acquire()
# 解锁
cond.release()
# 挂起线程,直到收到一个 notify 通知才会被唤醒
cond.wait()
# 唤醒一个 Condition 的 waiting 池中的线程
cond.notify()
# 唤醒所有 Condition 的 waiting 池中的线程
cond.notify_all()
"""
import threading
import time
condition = threading.Condition()
products = 0
class Producer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products < 10:
products += 1
print("Producer(%s):"
" deliver one, now products:%s" %
(self.name, products))
condition.notify()
else:
print("Producer(%s):already 10,"
" stop deliver, now products:%s" %
(self.name, products))
condition.wait()
condition.release()
time.sleep(2)
class Consumer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products > 1:
products -= 1
print("Consumer(%s):consume one,"
" now products:%s" %
(self.name, products))
condition.notify()
else:
print("Consumer(%s):only 1,"
" stop consume, products:%s" %
(self.name, products))
condition.wait()
condition.release()
time.sleep(2)
# if __name__ == "__main__":
# for p in range(0, 5):
# p = Producer()
# p.start()
#
# for c in range(0, 2):
# c = Consumer()
# c.start()
"""
互斥锁的使用:
互斥锁需要成对出现,否则会出现死锁的问题。
# 生成互斥锁对象
lock = threading.Lock()
# 获取锁,未获取到程序将会阻塞(当一个线程在执行被上锁的代码块时,将不允许切换到其他线程)
lock.acquire()
# 释放锁
lock.release()
# 判断该锁对象是否处于上锁状态
lock.locked()
"""
lock = threading.Lock()
NUM = 0
print("lock status: %s" % lock.locked())
import inspect
class LOCK_DEMO(object):
def __init__(self, lock):
self.lock = lock
# 动态获取当前执行的函数名
def get_current_function_name(self):
return inspect.stack()[1][3]
def add(self):
lock.acquire()
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
global NUM
for i in range(1000000):
NUM += 1
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
lock.release()
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
def add_with(self):
global NUM
with lock:
# 自动加锁
for i in range(1000000):
NUM += 1
# 自动解锁
def delete(self):
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
lock.acquire()
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
global NUM
for i in range(1000000):
NUM -= 1
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
lock.release()
print("lock status: %s in %s" % (lock.locked(), self.get_current_function_name()))
def run(self):
t1 = threading.Thread(target=self.add_with)
t2 = threading.Thread(target=self.delete)
t1.start()
t2.start()
t1.join()
t2.join()
print("NUM is: %s" % NUM)
LOCK_DEMO(lock).run()
"""
死锁现象
一般来说,形成死锁有两种形式
① 一个线程里面嵌套获取一把互斥锁。
② 多个线程不按顺序同时获取多个锁,
例如:线程1嵌套获取ab两个锁,线程2嵌套获取ba两个锁,当线程1获取到了a在等待b,而线程2获取到了b在等待a,两个线程就形成了一个循环等待的圆,从而形成死锁。
对于第一种情况,可以使用可重入锁(RLOCK)。
对于第二情况,其实和 mysql 中的死锁性质差不多,因争夺资源而造成的一种死循环,保证多个线程获取锁的顺序是同样的即可避免这种情况,即获取锁和释放锁要成对出现。
"""