def transaction(self, *args, **kwds):
        """Call this method to send the given args on the wire and
        wait for a response"""
        evt = threading.Event(self.__lock)

        # Allocate a transaction ID
        self.__lock.acquire()
        try:
            xid = self.__idgen.next()
            assert xid not in self.__waitq
            self.__waitq[xid] = [evt, None] # If except: means MUX stopped
        except AttributeError:
            raise EOFError("MUX has been stopped.")
        finally:
            self.__lock.release()

        # Send the request
        self._send((xid, args, kwds))

        # Wait for the answer
        evt.wait()

        # Return the answer/raise the exception to the caller
        self.__lock.acquire()
        try:
            # Retrieve the result
            try:
                result = self.__waitq[xid][1]
            except (AttributeError, IndexError):
                raise EOFError("MUX has been stopped.")
            except:
                print "EX", self.__waitq

            # Work done
            del self.__waitq[xid]

            # Reformat the result
            xid_, result_ = result
            assert xid_ == xid, \
                   "Expected txn id %s != received (%s)" % (xid, xid_)
            
            status, details = result_
            if status == "OK":
                return details
            elif status == "EXCEPTION":
                raise details
            else:
                raise RuntimeError("Invalid status %s !" % repr(status))
            return result
        finally:
            self.__lock.release()
Call this method to send the given args on the wire and
        wait for a response
recipes/Python/576520_Multithreaded_MultiplexerDemultiplexer_allow/recipe-576520.py