# 1、同步锁

acquire() 方法:只有一个线程能成功的获取锁，按先后顺序 其他线程只能等待。release() 方法：线程释放。这把锁不允许在同一线程中被多次acquire()。

import threading
import time

def check():
global number
lock.acquire()  # 对临界资源进行加锁
temp = number
time.sleep(0.01)
number = temp-1
lock.release()

l = []
number = 100
# 实例一把锁
for i in range(100):
t.start()
l.append(t)

for t in l:
t.join()
print(number)



# 2、递归锁(解决死锁问题)

acquire()方法和release()方法必须成对出现，即调用了n次acquire，必须调用n次的release才能真正释放所占用的锁。

### 死锁：当一个或多个进程等待系统资源，而资源又被进程本身或其它进程占用时，就形成了死锁。

import time

def run(self):
self.actionA()
self.actionB()

def actionA(self):
LockA.acquire()
time.sleep(1)
LockB.acquire()
time.sleep(0.)
LockB.release()
LockA.release()

def actionB(self):
LockB.acquire()
time.sleep(1)
LockA.acquire()
time.sleep(0.1)
LockA.release()
LockB.release()

if __name__ == '__main__':
L = []
for i in range(5):
t.start()
L.append(t)
for t in L:
t.join()
print('ending')



import time

def run(self):
self.actionA()
self.actionB()

def actionA(self):
LockA.acquire()
time.sleep(1)
LockA.acquire()
time.sleep(0.)
LockA.release()
LockA.release()

def actionB(self):
LockA.acquire()
time.sleep(1)
LockA.acquire()
time.sleep(0.1)
LockA.release()
LockA.release()

if __name__ == '__main__':
#   获得一把锁
L = []
#   实例线程对象
for i in range(5):
t.start()
L.append(t)
for t in L:
t.join()
print('ending')

# 3、信号量

import threading
import time

def check():
# 当进来一个变量，就会减一，一共有5把锁
if semaphore.acquire():
time.sleep(3)
# 每释放一把锁就会加一
semaphore.release()
#         最后显示会每三秒出5个结果

if __name__ == '__main__':
L = []
# 创建5个信号量，信号量也是一种锁
for i in range(100):
t.start()
L.append(t)
for t in L:
t.join()
print('end')


# 4、同步对象Event

wait()方法：没有设定标志位就会卡住，一旦被设定等同于pass。set()方法：设定标志位。clear()方法：清楚标志位。is_set()方法：是否设置。

import time

def run(self):
print("加班加班")
#  检验是否设置标志位
print(event.is_set())
#  设置标志位
event.set()
time.sleep(3)
# 清空标志位
event.clear()
print('加班结束')
event.set()

def run(self):
#       等待设置标志位，如果设置，此语句相当于pass
event.wait()
print("命苦啊")
time.sleep(1)
event.clear()
event.wait()
print("OH yeah")

if __name__ == '__main__':
L = []
#   创建一个同步对象
for i in range(5):
L.append(Worker())
L.append(Boss())
for t in L:
t.start()
for t in L:
t.join()
print("end")

# 5、生产者消费者模型

（1）：队列：线程队列一种数据结构，是多线程的、安全的。列表是线程不安全的。

队列的模式：1、先进先出   2、先进后出   3、按优先级。

import queue

# 创建一个队列先进先出
q = queue.Queue(3)

# q = queue.LifoQueue()   创建先进后出队列。（栈）later in first out
# q = queue.PriorityQueue()  创建一个按优先级顺序的队列

# 添加数据  当超过队列大小时，就会卡住put。后面如果加上false参数就会在满的时候报错。
q.put(1)
q.put("csdn")
q.put({"name":"2333"})
q.put("baba")

# print(q.qsize())   不是最大值，而是当前队列有多少个元素。
# print(q.maxsize)   队列的最长度
# print(q.full())   队满
# print(q.empty())   队空

while 1:
print("+++++++++")
#   取数据，没数据的时候会一直卡住，一直等到有添加值。(另外的一个线程可以继续添加值)。后面如果加上false参数就会在满的时候报错
print(q.get())
print("---------")

q.put([1,1])

(2)Producer-consumer problem：

import time, threading, queue, random

def producer(name):
count = 0
while count < 10:
print("making....")
# 随机数范围1--2
time.sleep(random.randrange(3))
q.put(count)
print("{}做好了第{}个包子".format(name,count))
count += 1
q.join()

def consumer(name):
count = 0
while count < 10:
time.sleep(random.randrange(4))
print('waiting')
# q.join()     没有信号会卡住，有人给信号就往下执行
data = q.get()
print("{}正在吃第{}个包子".format(name,data))
count += 1

if __name__ == '__main__':
q = queue.Queue()
t1.start()
t2.start()
t3.start()
t4.start()