简体   繁体   English

条件变量不保持两个线程之间的等待

[英]condition variable not holding wait across two threads

Stumped on this thread sync I'm encountering. 我遇到了这个线程同步问题。 Basically, I'm writing to a out buffer, and waiting on a condition variable until the read buffer is populated with a response from a socket. 基本上,我正在写出缓冲区,并等待条件变量,直到读取的缓冲区中填充了套接字的响应。 It's an incredibly simple thread sync. 这是一个非常简单的线程同步。

def write_wait_response(self, buffer, timeout=30):
        '''
            Write and wait for response
            Params:
                Buffer BYTE encoded data
                Timeout timeout to wait for response
            Returns: 
                response str if successful
        '''
        self.buffer = buffer

        if self.waitLock(timeout):
            # condition var was signaled, we can return a response
            readbuf = bytes(self.readbuffer)
            self.readbuffer = b''
            return readbuf
        else:
            print("AsyncClientSocket: No response recieved from {} in {} seconds, dumping buffer".format(
                    self.sa, timeout))
            self.buffer = ''
            raise TimeoutError("AsyncClientSocket Timed Out")

def handle_read(self):
        self.readbuffer, address = self.recvfrom(2048)
        print(self.readbuffer)
        print("notifying")
        self.cond.notifyAll() 

Seems straightforward enough, right? 看起来很简单,对吧? There's 1 thread waiting on the condition variable, and 1 thread (asyncore async callback loop) that will populate self.readbuffer and notify on the condition variable. 有1个线程在条件变量上等待,有1个线程(异步异步回调循环)将填充self.readbuffer并通知条件变量。 Even more curious : if I do a time.sleep() instead of using a condition variable, I get a perfectly populated self.readbuffer on the calling thread of write_wait_response(). 更奇怪的是:如果我执行time.sleep()而不是使用条件变量,则在write_wait_response()的调用线程上会得到一个填充良好的self.readbuffer。 Obviously this is not a solution I can accept. 显然,这不是我可以接受的解决方案。

Here's what I'm expecting is happening: 这是我期望发生的事情:

  1. Call to write_wait_response(buffer), this writes to buffer and waits on self.cond 调用write_wait_response(buffer),这将写入缓冲区并等待self.cond
  2. asyncore callback loop calls handle_write, writes bytes to socket. 异步回调循环调用handle_write,将字节写入套接字。
  3. Server receives bytes, writes response. 服务器接收字节,写入响应。
  4. asyncore callback loop sees bytes on the socket, reads into self.readbuffer, notifies cv asyncore回调循环在套接字上看到字节,读入self.readbuffer,通知cv
  5. ?????????? ?????????? write_wait_response should unblock? write_wait_response应该解锁吗?

Console output: 控制台输出:

waiting <- thread 1 waiting on CV
AsyncClientSocket: writing 5 bytes <- thread 2: handle_write
b'200,2' <- thread 2: that's the server response
notifying <- thread 2: that's handle_read attempting to notify the held CV

error: uncaptured python exception, closing channel <my_socket_stuff.AsyncClientSocket connected 127.0.0.1:50000 at 0x1051bf438> (<class 'RuntimeError'>:cannot notify on un-acquired lock

Note: at the end of this log, thread 1 is STILL waiting on self.cond. 注意:在此日志的末尾,线程1仍在self.cond上等待。 What's going on? 这是怎么回事?

Full class: 全班:

class AsyncClientSocket(asyncore.dispatcher):
    def __init__(self, socketargs):
        asyncore.dispatcher.__init__(self)
        family, type, proto, canonname, sa = socketargs
        self.sa = sa
        self.create_socket(family, type)

        if type == socket.SOCK_STREAM:
            self.connect( sa )
        elif type == socket.SOCK_DGRAM:
            pass

        self.buffer = b''
        self.lock = threading.Lock()
        self.cond = threading.Condition(self.lock)
        self.readbuffer = b''

    def write_wait_response(self, buffer, timeout=30):
        '''
            Write and wait for response
            Params:
                Buffer BYTE encoded data
                Timeout timeout to wait for response
            Returns: 
                response str if successful
        '''
        self.buffer = buffer

        if self.waitLock(timeout):
            # condition var was signaled, we can return a response
            readbuf = bytes(self.readbuffer)
            self.readbuffer = b''
            return readbuf
        else:
            print("AsyncClientSocket: No response recieved from {} in {} seconds, dumping buffer".format(
                    self.sa, timeout))
            self.buffer = ''
            raise TimeoutError("AsyncClientSocket Timed Out")

    def waitLock(self, timeout):
        '''
            Wait for timeout seconds on CV
        '''
        try:
            self.cond.acquire()
            print("waiting")
            return self.cond.wait(timeout)
        finally:
            self.cond.release()


    def handle_connect(self):
        pass

    def handle_close(self):
        self.close()

    def handle_read(self):
        self.readbuffer, address = self.recvfrom(2048)
        print(self.readbuffer)
        print("notifying")
        self.cond.notifyAll() 

    def writable(self):
        return (len(self.buffer) > 0)

    def handle_write(self):
        print("AsyncClientSocket: writing {} bytes".format(len(self.buffer)))
        self.readbuffer = b''
        sent = self.sendto(self.buffer, self.sa)
        self.buffer = self.buffer[sent:]

Figured it out. 弄清楚了。 This isn't related to asyncore. 这与异步无关。 I was just signaling the condition variable incorrectly. 我只是在错误地指示条件变量。 The python3 threading api doc says the calling thread of notify() must acquire the underlying lock which makes sense, wouldn't want two producers to notify on the same condition variable. python3线程API文档说,notify()的调用线程必须获取有意义的基础锁 ,而不希望两个生产者在同一条件变量上进行通知。 Would want one to block on the critical section while the other performs its task. 希望其中一个阻止关键部分,而另一个则执行其任务。

def handle_read(self):
    try:
        self.cond.acquire()
        self.readbuffer, address = self.recvfrom(2048)
        print(self.readbuffer)
        self.cond.notify() 
    finally:
        self.cond.release()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM