Is closesocket thread safe?
Asked Answered
B

2

6

Is it safe if I want to call closesocket() on a server socket from 1 thread which is separate from another thread which runs the server using the same server socket?

Brooklime answered 25/3, 2012 at 15:5 Comment(4)
You might want to rethink why you have multiple threads accessing the same socket. Perhaps it might be better to have some state flag that can inform the other threads that a connection is dying, but only have one thread actually interact with the socket.Mankind
@KerrekSB - usually, there is more than one thread accessing the socket because one thread performs blocking reads and another thread writes. This is safe/normal. A state flag is not useful if the thread/s are stuck on blocking calls.Topper
@MartinJames: although that practice is "safe" from the socket's point of view, it's very hard to get that scenario right (at least, it's a lot harder than it seems at first glance), precisely because there is great difficulty in synchronizing threads that are stuck in a blocking call. In any case, the application design should make it obvious who owns the socket, and "whoever finishes last" is really a good choice.Bis
What great difficulty? Usually, it's the read thread that is stuck. No matter whether the socket excepts/errors because its peer has closed the connection or because some other local thread has closed the socket, the problems are the same and, yes, it can be awkward if there are lists of socket objects etc, (eg. chat servers).Topper
B
5

The call itself is thread-safe, but the practice is not. Whenever you're deallocating a resource whose identifier could be reused after it's deallocated, you must synchronize with all threads that could possibly use it. Otherwise, it's possible that, after the resource is deallocated, a new resource (in your case, socket) could be allocated with the same identifier (socket number), and code intending to access the (now closed) server socket could end up operating on a different socket.

The degree to which this is dangerous (and whether it can happen at all) depends a lot on your code. It might not happen if you never create any more sockets after closing the server socket. But it's still conceptually very wrong, and anyone competent reviewing your code would consider this very bad.

Edit: The solution to problems like this is protection of the resource descriptor (not the resource itself) with a reader-writer lock (rwlock). Accessing the resource descriptor (the integer variable holding the socket number, in your case) requires holding a "read" lock on it, whether you'll be performing input or output or other operating using the resource it refers to. Deallocating the resource (and storing a sentinel value like -1 in the variable holding the descriptor) requires a write lock.

Burdick answered 25/3, 2012 at 16:7 Comment(5)
That's what 'TIME_WAIT' is for. If there is some higher-level mapping, (eg. a socket library allocates a socket context object), and fails to ensure that such contexts cannot be re-used, that is not within the purview of the OP question. If this approach is considered wrong, then maybe someone might like to suggest an alternative, (one that does not involve a redesign of a synch server as async and does not require CPU-wasting short timeouts on the socket to check a flag).Topper
No, it's completely unrelated to TIME_WAIT. I am not talking about the port being reused, which is no problem. I'm talking about the socket number (on POSIX this would be a file descriptor, but on Windows they're separate), which is an integer local to the process identifying an open socket, being reused. This has absolutely nothing to do with TIME_WAIT.Burdick
It is related, though not directly. It's a resource where there may possibly be some doubt about when it can be re-used. A common way round this problem is to put the resource on a timer queue until it is beyond reasonable probablilty that re-use may cause a problem, (TCP TIME_WAIT). In the case of socket handles, the issue is normally even easy to control without timeouts, eg. by removing the handle from whatever thrad-safe list it's in. Just because something can be misused does not mean that one should never do it, especially if there is no reasonable alternative.Topper
TIME_WAIT is not a timer queue on the socket handle. It's a timer queue on the address/port, and it's completely unrelated to the issue at hand. The issue at hand is an example of a completely general resource-deallocation issue with concurrency that has nothing whatsoever to do with sockets, and I explained the canonical/universal lightweight solution already (rwlocks).Burdick
Could you clarify this a bit further? What happens if the other thread is in the middle of a recv call on the socket?Doviedow
T
1

Yes, it's not a problem. Naturally, there will be exceptions/errors generated in the other thread/s that have calls outstanding on the socket, but the network stack itself, (which has to be thread-safe because of all the different processes/threads that are normally using it), will not be damaged.

Topper answered 25/3, 2012 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.