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/ -- http://mail.python.org/mailman/listinfo/python-list