簡體   English   中英

多線程-在Python中使用條件和事件在兩個線程之間交替

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM