This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author mpb
Recipients mpb
Date 2013-11-09.03:57:46
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1383969468.97.0.110285365425.issue19530@psf.upfronthosting.co.za>
In-reply-to
Content
I have a multi-threaded application.
A background thread is blocked, having called recvfrom on a UDP socket.
The main thread wants to cause the background thread to unblock.
With TCP sockets, I can achieve this by calling:
sock.shutdown (socket.SHUT_RD)

When I try this with a UDP socket, the thread calling shutdown raises an OS Error (transport end point not connected).

The blocked thread does unblock (which is helpful), but recvform appears to return successfully, returning a zero length byte string, and a bogus address!

(This is the opposite of the TCP case, where the blocked thread raises the exception, and the call to shutdown succeeds.)

In contrast, sock.close does not cause the blocked thread to unblock.  (This is the same for both TCP and UDP sockets.)

I suspect Python is just exposing the underlying C behavior of shutdown and recvfrom.  I'd test it in C, but I'm not fluent in writing multi-threaded code in C.

It would be nice if the recvfrom thread could raise some kind of exception, rather than appearing to return successfully.  It might also be worth reporting this bug upstream (where ever upstream is for recvfrom).  I'm running Python 3.3.1 on Linux.

See also this similar bug.
http://bugs.python.org/issue8831

The Python socket docs could mention that to unblock a reading thread, sockets should be shutdown, not closed.  This might be implied in the current docs, but it could be made explicit.  See:

http://docs.python.org/3/library/socket.html#socket.socket.close

For example, the following sentence could be appended to the Note at the above link.  "Note: (...)  Specifically, in multi-threaded programming, if a thread is blocked performing a read or write on a socket, calling shutdown from another thread will unblock the blocked thread.  Unblocking via shutdown seems to work with TCP sockets, but may result in strange behavior with UDP sockets."

Here is sample Python code that demonstrates the behavior.

import socket, threading, time

sock = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sock.bind (('localhost', 8000))

def recvfrom ():
  for i in range (2) :
    print ('recvfrom  blocking ...')
    recv, remote_addr = sock.recvfrom (1024)
    print ('recvfrom  %s  %s' % (recv, remote_addr))

thread = threading.Thread ( target = recvfrom )
thread.start ()
time.sleep (0.5)

sock2 = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sock2.sendto (b'test', ('localhost', 8000))

time.sleep (0.5)

try:  sock.shutdown (socket.SHUT_RD)
except OSError as exc :  print ('shutdown  os error  %s' % str (exc))

sock.close ()

thread.join ()
print ('exiting')


----

And here is the output of the above code:

recvfrom  blocking ...
recvfrom  b'test'  ('127.0.0.1', 48671)
recvfrom  blocking ...
shutdown  os error  [Errno 107] Transport endpoint is not connected
recvfrom  b''  (59308, b'\xaa\xe5\xec\xde3\xe6\x82\x02\x00\x00\xa8\xe7\xaa\xe5')
exiting
History
Date User Action Args
2013-11-09 03:57:49mpbsetrecipients: + mpb
2013-11-09 03:57:48mpbsetmessageid: <1383969468.97.0.110285365425.issue19530@psf.upfronthosting.co.za>
2013-11-09 03:57:48mpblinkissue19530 messages
2013-11-09 03:57:46mpbcreate