Using thread in an asyncronous application

G

Giampaolo Rodola'

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/
 
A

Aaron Brady

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

I found it hard to read through it. Do you have a smaller abstract
example?
 
G

Giampaolo Rodola'

I found it hard to read through it.  Do you have a smaller abstract
example?- Nascondi testo citato

- Mostra testo citato -

Yeah, sure. I removed all the confusing stuff. Though I didn't tried
it it should work:


class ThreadedFTPServer(FTPServer, threading.Thread):

def __init__(self, address, handler):
FTPServer.__init__(self, address, handler)
threading.Thread.__init__(self)
self.__serving = False

def start(self):
threading.Thread.start(self)

def run(self):
self.__serving = True
while self.__serving:
self.__lock.acquire()
FTPServer.serve_forever(self, timeout=1, count=1)
self.__lock.release()
FTPServer.close_all(self, ignore_all=True)

def stop(self):
if not self.__serving:
raise RuntimeError("Server not started yet")
self.__serving = False
self.join()


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

Aaron Brady

Yeah, sure. I removed all the confusing stuff. Though I didn't tried
it it should work:

class ThreadedFTPServer(FTPServer, threading.Thread):

    def __init__(self, address, handler):
        FTPServer.__init__(self, address, handler)
        threading.Thread.__init__(self)
        self.__serving = False

    def start(self):
        threading.Thread.start(self)

    def run(self):
        self.__serving = True
        while self.__serving:
            self.__lock.acquire()
            FTPServer.serve_forever(self, timeout=1, count=1)
            self.__lock.release()
        FTPServer.close_all(self, ignore_all=True)

    def stop(self):
        if not self.__serving:
            raise RuntimeError("Server not started yet")
        self.__serving = False
        self.join()

--- Giampaolohttp://code.google.com/p/pyftpdlib/

Well I'm just one person, but I like it. Not sure if you want double-
underscores on your variable names. And not sure you have to override
'start' just to call the base method... does FTPServer have a 'start'
method? How do you resolve those in general... setting the MRO?
Setting the method to the base method, 'start= threading.Thread.start'?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top