Using thread in an asyncronous application

Giampaolo Rodola' gnewsg at gmail.com
Thu Nov 27 10:03:10 EST 2008


Hi,
I'm the maintainer of an asynchronous FTP server implementation based
on asyncore.
Some days ago I thought it would be interesting to add a class
offering the possibility to run the asyncore loop into a thread so
that a user can run the server without blocking the entire
application.
It could be useful, for example, in case someone wants to integrate a
GUI.

Since I'm not good with multi-threaded programming I'd like some
opinions about the code I'm going to paste below.

The FTPServer class that I inherited in my subclass is the
"dispatcher" which listens on port 21 dispatching the incoming
connection to an "handler".
The polling loop (FTPServer.serve_forever()) is wrapped in the run
method.
As you can see I acquire and release the lock (threading.Lock) every
time I call the polling loop.
My question is: is that really necessary?
Should I expect some weird behavior by running the main loop into a
thread like I did?


Thanks in advance



class ThreadedFTPServer(FTPServer, threading.Thread):
    """A modified version of the FTPServer class which wraps the
    'serve_forever' polling loop into a thread.

    The instance returned can be used to start(), stop() and
    eventually re-start() the server.
    """

    def __init__(self, address, handler):
        FTPServer.__init__(self, address, handler)
        threading.Thread.__init__(self)
        self.__lock = threading.Lock()
        self.__flag = threading.Event()
        self.__serving = False
        self.__stopped = False

    def __repr__(self):
        status = [self.__class__.__module__ + "." +
self.__class__.__name__]
        if self.__serving:
            status.append('active')
        else:
            status.append('inactive')
        status.append('%s:%s' %self.socket.getsockname()[:2])
        return '<%s at %#x>' % (' '.join(status), id(self))

    def start(self, timeout=1, use_poll=False, map=None):
        """Start serving until an explicit stop() request.
        Polls for shutdown every 'timeout' seconds.
        """
        if self.__serving:
            raise RuntimeError("Server already started")
        if self.__stopped:
            # ensure the server can be started again
            ThreadedFTPServer.__init__(self, self.socket.getsockname
(),
                                       self.handler)
        self.__timeout = timeout
        self.__use_poll = use_poll
        self.__map = map
        threading.Thread.start(self)
        self.__flag.wait()

    server_forever = start

    def run(self):
        self.__serving = True
        self.__flag.set()
        while self.__serving:
            self.__lock.acquire()
            FTPServer.serve_forever(self, timeout=self.__timeout,
count=1,
                                    use_poll=self.__use_poll,
map=self.__map)
            self.__lock.release()
        FTPServer.close_all(self, ignore_all=True)

    def stop(self):
        """Stop serving (also disconnecting all currently connected
        clients) by telling the serve_forever() loop to stop and
        waits until it does.
        """
        if not self.__serving:
            raise RuntimeError("Server not started yet")
        self.__serving = False
        self.__stopped = True
        self.join()

    close = close_all = stop



--- Giampaolo
http://code.google.com/p/pyftpdlib/



More information about the Python-list mailing list