多线程-在Python中使用条件和事件在两个线程之间交替执行

多线程-在Python中使用条件和事件在两个线程之间交替执行,python,multithreading,events,synchronization,Python,Multithreading,Events,Synchronization,我正在尝试编写一个程序,我希望使用它在两个线程(thread1和thread2)之间交替运行。棘手的部分是线程应该首先开始执行,必须是thread1。 这是我目前掌握的代码: Class Client: #member variables def sendFile(self,cv1,lock1): sent=0; while (i<self.size): message = self.data[i:1024+i]

我正在尝试编写一个程序,我希望使用它在两个线程(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()
类客户端:
#成员变量
def发送文件(自身、cv1、锁定1):
发送=0;

而(i同步至少有两个问题

首先,您使用的
cv1
错误。您的接收线程必须围绕其cv循环,检查条件并每次调用
wait
。否则,您只是将cv用作断开的事件+锁组合。您没有这样的循环。更重要的是,您甚至没有需要等待的条件

第二,您使用的
lock1
错误。您的接收线程设置了事件,然后立即清除。但无法保证发送线程已经到达等待状态。(来自上一个问题的争用使这更成为一个问题,但即使您修复了它,这仍然是一个问题。)在多核机器上,它通常会及时到达,但“通常”在线程编程中甚至比从不更糟糕。因此,在接收线程完成清除后,发送线程最终将进入等待状态,因此它将永远等待。同时,接收线程将等待发送线程的通知,这是永远不会发生的。因此,您处于死锁状态

作为将来的参考,在每个阻塞操作(尤其是同步操作)之前和之后添加
print
语句将使调试变得非常困难:您将看到接收线程的最后一条消息是“receive waiting on cv1”,而发送线程的最后一条消息是“send waiting on lock1”显然,僵局在哪里


无论如何,我不确定“修复”一个没有条件的cv,或者一个您试图用作cv的事件意味着什么,因此我将演示如何使用两个cv编写合理的内容。在这种情况下,我们不妨使用一个前后翻转的标志作为两个cv的条件

在这里,我将修复一些使您的代码甚至不可测试的其他问题(例如,
I
从未初始化),并包括调试信息,以及我必须填写的内容,以使这成为一个完整的示例,但除此之外,我将尝试保留您的结构和无关的问题(就像
Client
是一个旧式类)完好无损


启动服务器,启动客户机,服务器将计数为672,客户机将计数为673(因为您的代码基于1计数),673对平衡的消息和最后一个“成功发送文件!”。(当然,客户端将永远挂起,因为
receiveAck
无法完成,而服务器将永远挂起,因为我将其作为无限循环编写。)

我的第一个问题是,为什么要这样做?如果两个线程只是显式地交换控制权,那有什么意义呢?比如说,使用生成器可以更轻松地实现控制权?我只是简化了我的程序以便于理解。实际上,thread1使用UDP套接字发送数据包,而thread2使用相同的套接字ocket将收到该数据包的确认。除非收到前一个数据包的确认,否则线程1不应继续。我希望你明白我的意思,但即使你不明白,我也会要求你忽略我在两个线程之间交替的目的,并请你帮我解决我面临的问题。听起来相当有序…为什么使用线程,而不是简单地使用阻塞IO?阻塞,直到您得到确认,然后继续循环中的下一个数据包,为什么使用线程?一个明显的问题是您没有在服务员端正确使用条件。您必须有一个循环来检查条件并调用
cv1.wait()
acquire
/
release
对中,或者您只是将cv用作断开的事件+锁组合。更重要的是,您首先看不到有任何条件可以使用cv进行保护。例如,如果套接字未阻塞,并且您检查了
recvfrom
是否未准备就绪,那么这将是一件值得注意的事情用简历进行保护,但你没有这样做。另外,给我们一个完整的运行示例(an)我们可以调试会使事情变得更容易;我们可以找出错误所在,而不是猜测代码中可能出现的错误。非常感谢您的回答。它与我原来打算使用的代码一样完美。对于没有提供完整功能的代码,我深表歉意,我下次会小心。至于使用阅读来执行一个相当连续的任务,这实际上是我正在处理的任务的一个要求!
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)