确定代码非常基本。由于我使用多个线程,并且我想要它们之间的共享变量,我使用的是全局。
当我点击“C”时,为什么ThreadClass中的代码有时不会执行?我知道这是一个并发问题,但我不确定如何解决它。我已经阅读了信号量并最近锁定了,但我现在还不确定如何实现它。 欢迎任何建议。
import threading
buff_list = []
class ThreadClass(threading.Thread):
global buff_list
def run(self):
while (True):
if ("C" == raw_input()):
buff_list.append("C")
print buff_list
class ThreadClass2(threading.Thread):
global buff_list
def run(self):
while(True):
if ("B" == raw_input() and len(buff_list) > 0):
buff_list.pop()
print buff_list
a = ThreadClass()
b = ThreadClass2()
a.start()
b.start()
答案 0 :(得分:6)
这里有两个同步问题。
让我们首先处理更容易的事情,即您分享两个线程争夺的全局buff_list
这一事实。没有什么能阻止一个线程同时尝试append
其他线程pop
,这是非法的。而且,即使你很幸运并且没有发生,pop
也可以在<{em> append
之前来。
解决此问题的最简单方法是使用Queue
,它会自动同步:
buff_list = Queue.Queue()
然后只使用put
代替append
,get
代替pop
。
但是,如果你想自己学习这些东西,可以采用两种方法。
首先,您可以使用Lock
。 (您也可以使用RLock
,但暂时忘记这一点。)这可以确保一次只有一个线程访问buff_list
。
buff_lock = threading.Lock()
buff_list = []
现在,每当你追加或弹出时,只需抓住锁:
with buff_lock:
buff_list.append("C")
with buff_lock:
val = buff_list.pop()
但是这不会确保弹出的代码等到有东西出现。如果您想这样做,请使用Condition
:
buff_cond = threading.Condition()
现在:
with buff_cond:
buff_list.append("C")
buff_cond.notify()
with buff_cond:
while not buff_list:
buff_cond.wait()
value = buff_list.pop()
第二个问题是您隐式共享sys.stdin
,因为两个线程都在调用raw_input
。除非你有某种方法来同步事物,以便每个线程都知道它应该何时获得下一个输入(并且可能很难描述,如果可以的话,你可以将它变成代码&# 39;描述它),这可能是有效的 - 每次你输入C
时,错误的线程都会有50/50的机会获得它。
因此,正如kirelagin建议的那样,你需要只为一个线程负责I / O.最简单的方法是再次使用Queue
,并使一个线程put
任何它不使用的输入,另一个线程可以从队列中get
。
答案 1 :(得分:4)
嗯,你永远不知道哪个类的实例得到了你的输入。如果您点击“C”并且ThreadClass2
正在阅读您的输入,则只有"B" == raw_input()
False
才会执行任何操作。
一个线程应该负责I / O.
答案 2 :(得分:0)
除了之前的回复中所说的内容之外,我还想补充一点,线程模块还支持在所有其他语言中实现的更原始的机制,例如Semaphore Objects。
这是计算机科学史上最古老的同步原语之一,由荷兰早期计算机科学家Edsger W. Dijkstra发明(他使用P()和V()而不是获取()和释放( ))。
我认为深入学习线程的最佳方法是从头开始。