level 5
我有2个线程,一个存钱,每次存100,一个取钱,每次取100,让他们都执行100次,其中用到了Condition对象,实现一个存一个取,不存在同时存2次或取两次的情况。
但是呢,现在出现的问题是,没办法执行到100次,到六七十次就卡住了,没想明白为什么,也没办法调试,能给个思路吗??
2020年12月31日 09点12分
1
level 5
#!/usr/local/bin/python3
# coding=utf-8
import threading
class Account:
def __init__(self, card_id, balance):
self.card_id = card_id
self._balance = balance
self.cond = threading.Condition()
self._flag = False
# 取钱
def draw(self, balance):
self.cond.acquire() # 加绑定锁
try:
if not self._flag:
self.cond.wait()
else:
self._balance -= balance
self._flag = False
print("{}取钱成功{}元,余额{}元。".format(threading.current_thread().name, balance, self._balance))
self.cond.notify_all()
except:
print("未知错误!")
finally:
self.cond.release() # 释放绑定的锁
# 存钱
def deposit(self, balance):
self.cond.acquire() # 加绑定锁
try:
if self._flag:
self.cond.wait()
else:
self._balance += balance
self._flag = True
print("{}存钱成功{}元,余额{}元。".format(threading.current_thread().name, balance, self._balance))
self.cond.notify_all()
except:
print("未知错误!")
finally:
self.cond.release() # 释放绑定的锁
# 取钱多次
def draw_many(account, balance, n):
for i in range(n):
account.draw(balance)
print("取钱第{}次".format(i + 1))
# 存钱多次
def deposit_many(account, balance, n):
for i in range(n):
account.deposit(balance)
# print("存钱第{}次".format(i + 1))
if __name__ == "__main__":
account = Account("110", 0)
# 存钱线程
thread1 = threading.Thread(name="甲", target=deposit_many, args=(account, 800, 100))
# 取钱线程
thread2 = threading.Thread(name="乙", target=draw_many, args=(account, 800, 100))
thread1.start()
thread2.start()
2020年12月31日 09点12分
3
吧务
level 12
取钱刚好执行完self.cond.notify_all()时,存钱刚好执行完一轮,然后下一轮循环开始,然后进入了self.cond.wait()
try
。。self._balance += balanc
。。print("{}存钱成功{}元,余额{}元。".format(threading.current_thread().name, balance, self._balance))
。。self.cond.notify_all()
。。self.cond.wait(2)#加这里,设个timeout保险,取钱也一样这样改
except:
2020年12月31日 14点12分
5
不需要if else了
2020年12月31日 14点12分
@一周休七日 我没明白为什么卡住了,而且都是取完钱后卡住
2020年12月31日 16点12分
@陆玖Orzº 一个线程的wait在另一线程的线程唤醒执行后执行
2020年12月31日 20点12分
level 11
你这代码写的,有可能存钱次数和取钱次数不等,就卡在那了
2020年12月31日 15点12分
6
level 11
比如第5次去取钱,但是没钱了,然后线程挂起,再次被唤醒的时候,不走else块,相当于第5次啥也没干
2020年12月31日 17点12分
7
有点明白了,我就想问来着,当wait后,另一边调用唤醒这个线程的时候,这个线程是从哪里开始跑?
2020年12月31日 17点12分
从上次断的地方开始
2020年12月31日 17点12分
@蟒蛇与咖啡 是从wait那个部分开始跑吗,这样的话,100次确实是有损失部分else的判定
2020年12月31日 17点12分
@蟒蛇与咖啡 懂了,明天试试,多谢大佬,感激不尽🙏
2020年12月31日 17点12分
level 11
其实根本不需要flag变量,每次只需要钱判断够不够取就行了,不够就一直wait
2021年01月04日 02点01分
11
再请教一个问题哈,在执行lock.acquire()的时候,已经存在锁了,那么此线程后续会干嘛啊
2021年01月04日 02点01分
@蟒蛇与咖啡 是会阻塞吗?等锁消费后,再加锁进入。还是再加一把锁后阻塞,等上一把锁消费后,再进入
2021年01月04日 02点01分
level 7
就是加了一个互拆锁嘛,
创建一个唯一的互拆锁
你就算有一百个线程每次只有一个线程拿到锁了
就是这个理,在说py的线程都是假的
2021年01月04日 02点01分
12
再请教一个问题哈,在执行lock.acquire()的时候,已经存在锁了,那么此线程后续会干嘛啊
2021年01月04日 02点01分
@好男儿our加油 是会阻塞吗?等锁消费后,再加锁进入。还是再加一把锁后阻塞,等上一把锁消费后,再进入
2021年01月04日 02点01分