threading issue

I am putting together a threaded client/server program, which shows current throughput on the server screen.

The server receives the client connect and a thread is being spun up. That portion works just fine.

  • Client connect: Server says hello to client
  • The server starts a thread
  • The Client keeps on sending the the tx/rx info
  • Server shows the output on the screen

So far so good...

Here is the program, I want to keep track of the average for a specific period of time.

the class for the client:

class client(object):
    def __init__(self, name):
        self.name=name
        self.txtotal=0
        self.rxtotal=0
    def txrxinc(self, tx, rx):
        self.txtotal+=tx
        self.rxtotal+=rx
    def print_average(self):
        while True:
            time.sleep(AVERAGE)
            lock.acquire(True)
            rx_bytes, rx_kbytes, rx_mbytes=converter(self.rxtotal/AVERAGE)
            tx_bytes, tx_kbytes, tx_mbytes=converter(self.txtotal/AVERAGE)
            print socket.gethostbyaddr(clientaddress[0])[0]+"("+clientaddress[0]+")", "Average:", rx_bytes, rx_kbytes, rx_mbytes, tx_bytes, tx_kbytes, tx_mbytes
            self.txtotal=0
            self.rxtotal=0
            lock.release()

As you can see, "while True:" keeps on looping as its own thread. Every time the time.sleep(AVERAGE) hits, it is supposed to print out the average on the screen.

Now, the above function gets called like this. I will only show the first couple of lines, because it just hangs with "while True:" in place

def replyback(clientsocket, clientaddress):
    CLIENTS[clientaddress[0]]=client(clientaddress[0])
    ThroughPutThread=threading.Thread(target=CLIENTS[clientaddress[0]].print_average())
    ThroughPutThread.daemon=True
    ThroughPutThread.start()
    print CLIENTS

"print CLIENTS" gets never started, if the "while True:" loop is active. If I take "while True:" out, we only run "print_average" once and the server keeps on getting all the client rx/tx info.

In short, If I disable the loop, everything works.

I am not sure what I am doing wrong.... It's like it is not running as a thread.

12 comments · 100% upvoted · other discussions

comments

zifnabxar

It looks like the client thread is blocked on the lock.acquire() call. How are you creating the lock? Is anyone else acquiring it? When/how do they release it?

It would also help to know the version of Python and your OS. Python threading/multiprocessing has some annoying quirks.

zifnabxar

Quick follow-up. Do you know what I mean when I say "is blocked on the lock.acquire() call"? Judging from what you're doing and how you've explained yourself, I assume that's the case, but I want to make sure.

StorageNinja [OP]

Initially, I thought the "lock" may be causing this. For testing purposes, I kicked it out, but it was still behaving the same. Currently, I am using only one client for my testing. This is the only "lock" statement. The "lock" is just around the print statements, which will print out the average.

I am writing the script in a lab env. on linux / python 2.7.11.

I may have found something, but this makes this even stranger. For the threading starting procedure, I added "name=".

Server start:

while True:
    clientsocket, clientaddress=serversocket.accept()
    print "Connection from", socket.gethostbyaddr(clientaddress[0])[0]+"("+clientaddress[0]+")", "on port", str(clientaddress[1])+"."
    t=Thread(name="connection thread "+socket.gethostbyaddr(clientaddress[0])[0], target=replyback, args=[clientsocket, clientaddress])
    t.daemon=True
    t.start()

Pretty simple, we keep on looping waiting for connections. As soon as we get a connection, we create a thread and assign it the name "connection thread some.server.com"

When it calls replyback, I added a print out of the thread:

def replyback(clientsocket, clientaddress):
    print "reply back: ", current_thread().name
    CLIENTS[clientaddress[0]]=client(clientaddress[0])
    ThroughPutThread=Thread(name="Through Put thread"+clientaddress[0],target=CLIENTS[clientaddress[0]].print_average())
    ThroughPutThread.daemon=True
    ThroughPutThread.start()

This prints out "connection thread some.server.com" Awesome!

The next thread creation starts with added name as well:

ThroughPutThread=Thread(name="Through Put thread"+clientaddress[0],target=CLIENTS[clientaddress[0]].print_average())

Now, if it calls object print_average(), I added another

print "print average: ",current_thread().name

I would expect a print out like this "Through Put thread some.server.com". The thing is... it replies back "connection from thread some.server.com"

This would explain why this is not running as a new thread.

The new "thread" runs under the initial thread id!

Right? follow up question? How to fix this? lol

zifnabxar

What do you mean by "the next thread creation"? Clearly client isn't being called, but it's hard for me to understand why without seeing more of your code.

Is there any chance I could see all of your code? Either a github repo or a pastebin? Threading/multiprocessing is difficult to grok

StorageNinja [OP]
zifnabxar

If I run your code and then connect to it with my browser, I get what I believe is the correct response:

-> Create socket object
-> using port 55555
-> bind to rosalind on port 55555
-> waiting for up to 10 clients
-> getting an average every 10.0 seconds
Connection from localhost(127.0.0.1) on port 49380.
reply back:  connection thread localhost
print average:  connection thread localhost

print_average is being called. Is this not what you're seeing?