[英]Multithreading - Alternating between two threads using Conditions and Events in Python
我正在嘗試編寫一個程序,希望使用該程序在兩個線程thread1和thread2之間交替。 棘手的部分是,線程應該首先開始執行的必須是thread1。 這是我到目前為止的代碼:
Class Client:
#member variables
def sendFile(self,cv1,lock1):
sent=0;
while (i<self.size):
message = self.data[i:1024+i]
cv1.acquire()
BadNet.transmit(self.clientSocket,message,self.serverIP,self.serverPort)
cv1.notify()
cv1.release()
i = i+1024
sent+=1
lock1.wait()
print "File sent successfully !"
self.clientSocket.close()
def receiveAck(self,cv1,lock2):
i=0
while (1):
lock1.clear()
cv1.acquire()
cv1.wait()
print "\nentered ack !\n"
self.ack, serverAddress = self.clientSocket.recvfrom(self.buf)
cv1.release()
lock1.set()
if __name__ == "__main__":
lock1 = Event()
cv1 = Condition()
cv2= Condition()
client = Client();
client.readFile();
thread1 = Thread(target = client.sendFile, args=[cv1,lock1])
thread2 = Thread(target = client.receiveAck, args=[cv1,lock1])
thread1.start()
thread2.start()
thread1.join()
thread2.join()
我當前面臨的問題是,程序最初會在兩個線程之間交替(由控制台上的輸出確認),但是經過任意次迭代(通常在20到80之間)后,程序只是掛起,不再執行任何迭代。
同步至少有兩個問題。
首先,您使用的cv1
錯誤。 您的接收線程必須遍歷其cv,檢查條件並每次都調用wait
。 否則,您只是將簡歷用作損壞的事件+鎖組合。 您沒有這樣的循環。 更重要的是,您甚至沒有條件等待。
其次,您使用的lock1
錯誤。 您的接收線程設置事件,然后立即將其清除。 但是,不能保證發送線程已經等待。 (與前一個問題的競賽使這個問題成為更多問題,但是即使您將其解決也仍然是一個問題。)在多核計算機上,它通常會及時到達那里,但是“通常”甚至比從來沒有更糟。在線程編程中。 因此,最終在接收線程已經完成清除之后,發送線程將進入等待狀態,因此它將永遠等待。 同時,接收線程將等待發送線程通知,這將永遠不會發生。 所以你陷入僵局。
供以后參考,在每個阻塞操作(尤其是同步操作)之前和之后添加print
語句將使調試工作變得很多:您會看到接收線程的最后一條消息是“ receivewaiting on cv1”,而發送線程的最后一條消息是“發送在lock1上等待”,這顯然是死鎖所在的位置。
無論如何,我不確定“無條件”修復cv或您要用作cv的事件的含義,所以我將展示如何用兩個cv編寫有意義的內容。 。 在這種情況下,我們最好只使用來回翻轉的標志作為兩個cv的條件。
在解決這個問題時,我將修復一些其他問題,這些問題使您的代碼甚至無法測試(例如, i
從未初始化過),並包含調試信息,以及為使本示例完整而必須填寫的內容,但否則,我將盡力保留您的結構和不相關的問題(例如Client
是老式類)。
class Client:
def __init__(self):
self.clientSocket = socket(AF_INET, SOCK_DGRAM)
self.serverIP = '127.0.0.1'
self.serverPort = 11111
self.buf = 4
self.waitack = False
def readFile(self):
self.data = ', '.join(map(str, range(100000)))
self.size = len(self.data)
#member variables
def sendFile(self,cv1,lock1):
i = 0
sent=0
while (i<self.size):
message = self.data[i:1024+i]
print "s cv1 acquire"
with cv1:
print "s sendto"
self.clientSocket.sendto(message, (self.serverIP, self.serverPort))
self.waitack = True
print "s cv1 notify"
cv1.notify()
i = i+1024
sent+=1
print "s cv2 acquire"
with cv2:
print "s cv2 wait"
while self.waitack:
cv2.wait()
print "File sent successfully !"
self.clientSocket.close()
def receiveAck(self,cv1,lock2):
i=0
while (1):
print "r cv1 acquire"
with cv1:
while not self.waitack:
print "r cv1 wait"
cv1.wait()
print "r recvfrom"
self.ack, serverAddress = self.clientSocket.recvfrom(self.buf)
i += 1
print self.ack, i
print "r cv2 acquire"
with cv2:
self.waitack = False
print "r cv2 notify"
cv2.notify()
這是一個測試服務器:
from itertools import *
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 11111))
for i in count():
data, addr = s.recvfrom(1024)
print(i)
s.sendto('ack\n', addr)
啟動服務器,啟動客戶端,服務器將最多計數672,客戶端將最多計數673(因為您的代碼從1開始計數),其中包含673對平衡的消息對和“文件發送成功!”。 在末尾。 (當然,由於receiveAck
無法完成,因此客戶端將永遠掛起,而由於我將其編寫為無限循環,則服務器將永遠掛起。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.