1. 多线程加锁
在多线程加锁的过程中,要注意如下两个核心关键点:
加锁的位置
,加锁的位置代表了一旦其中某一线程获取锁后,其他线程就会阻塞到此位置,当加锁的线程执行完毕释放锁后,其他线程会根据阻塞时的位置继续向向执行。加锁边界处理
, 在到达边界时,一旦某一线程完成任务后,其他阻塞的线程就不能继续完成任务,要考虑其他线程要退出任务。防止死锁
,正常情况下cpu执行一个锁要从加锁到释放锁这么一个原子性操作,若在加锁后还为解锁时,就退出任务,此时就变为死锁,自己和其他都一致会阻塞
举例说明:
import time
from threading import Thread,Lock,currentThread
import logging
FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
# logging.basicConfig(format=FORMAT,level=logging.INFO)
logging.basicConfig(format=FORMAT,level=logging.INFO)
cups = []
lock = Lock()
def worker(count=10):
logging.info("I'am working for CPU.")
flag = False
while not flag:
#如果len(cups)=999,线程1进入循环在此枷锁,
# 其他线程也进入此循环阻塞到此位置,若线程1执行完后,其他线程
#也要枪锁,因此要判断是否要cups.append(1),若已经达到1000,则跳过;
lock.acquire()
time.sleep(0.001)
print(len(cups))
if len(cups) >= 1000:
flag = True
#若此位置加break,尚未解锁就结束,形成死锁
#break
#达到100时,阻塞的线程进来后,要根据flag值判断是否在添加,若没有
#判断时,其他阻塞的线程进来依然会添加,因此会有错误
#cups.append(1)
#正确做法
if not flag:
cups.append(1)
print(currentThread())
lock.release()
logging.info('I finished. cups = {}'.format(len(cups)))
for _ in range(10):
Thread(target=worker,args=(1000,)).start()
2. 加锁类LOCK
acquire(blocking=Ture,timeout=-1)
- 默认情况下是阻塞状态,当无法获取到锁时,会一直处于阻塞状态,当然也可以设置timeout超时时间,到达超时时间立马退出
- 若blocking=False时,当没有获取到锁时,立马退出,无须阻塞等待
release
- 释放锁,可以从任何线程调用释放
- 已上锁的锁,会被重置为unlocked未上锁的锁上调用,抛出RuntimeError异常
3. 加锁作用
在多线程中,多线程同时处理一个公共变量时,线程A和线程B,如
当x = 0, x = x + 1时,尚未执行完成,切换另外一个线程x = x +1,本来应该是2,但是因为第一个线程x= x+ 1执行一半,因此x再次变为1
import threading
from threading import Thread,Lock
import time
class Counter:
def __init__(self):
self._val = 0
@property
def value(self):
return self._val
def inc(self):
self._val += 1
def dec(self):
self._val -= 1
def run(c,count=100):
for _ in range(count):
for i in range(-50,50):
if i < 0:
c.dec()
else:
c.inc()
c = Counter()
c1 = 100
c2 = 100
for i in range(c1):
Thread(target=run,args=(c,c2)).start()
print(c.value)
4. 可重入锁RLock
可重入锁当线程A中获取一次或多次锁lock,同时将同一把锁lock传递到另外一个线程B中,当线程A中不释放这把锁时,线程B中就因为这把锁无法使用,线程B就处于阻塞状态。
如:你拿一把锁链,把自行车多次上锁,但是你又想把这把锁锁另外一个自行车,肯定无法使用,因为锁还没有解开,所以另外一个自行车只能处于等待状态。
import threading
import time
lock = threading.RLock()
lock.acquire()
def worker(lock):
print("blocking ...")
lock.acquire()
print(threading.current_thread().ident)
print()
print("end blocking ...")
t = threading.Thread(target=worker,args=(lock,))
t.start()
print(lock)
t.join()
print("end")
#运行结果
blocking ...
<locked _thread.RLock object owner=8724 count=1 at 0x000001941A851C88>
##阻塞状态
5. condion
condion是条件通知机制,主要解决的问题是:生产者和消防者速度不匹配的问题,有了condion后,生产者生产完后,通知消费者来消费,这样更加高效的完成任务