Can I call sendto()
from other thread on socket, when main thread is blocked on select()
for same socket for checking readability? Is this behavior defined across different systems like linux or windows? Or do I have to always do socket related stuff (select()
/ sendto()
/ recvfrom()
) from single same thread only?

- 3,320
- 7
- 35
- 68
-
No, you can call it whenever you like. You don't need the selector's 'permission'. But if you're in blocking mode you might block, and if you're in non-blocking mode you might get EAGAIN/EWOULDBLOCK, and you'll need recourse to the selector at that point. – user207421 May 05 '20 at 05:59
3 Answers
I use such architecture in my application. I've checked in multiple sources (for Linux) and haven't found anything against it.
The only formal foundation proofing this concept is POSIX standard - it says that sendto()
as well as select()
are thread safe functions:
POSIX.1-2001 and POSIX.1-2008 require that all functions specified in the standard shall be thread-safe, except for the following functions
(sendto
and select
not listed) from https://linux.die.net/man/7/pthreads.
So if functions are thread-safe, it's internal structures are safely locked, then mixing these two functions should also be ok. However I don't think it's correct for mixing select()
with recvfrom()
. Maybe it will not corrupt program, but waking two waiting threads will generate race condition.
Regarding winsock, the documentation must be checked how it's implementation follows the POSIX standard. The only thing I've found is is winsock2 thread safe? , which partially anserwrs your question. In Linux you can examine it's opensource code: https://github.com/torvalds/linux/blob/master/net/socket.c https://github.com/torvalds/linux/blob/master/fs/select.c.
UPDATE: One more helpful link https://groups.google.com/forum/#!topic/comp.os.linux.networking/cLbMGRNw8EA

- 704
- 1
- 6
- 13
-
Your reasoning is flawed: Just because a function is "thread-safe" doesn't mean you can do anything with it. Being able to process multiple calls on _the_ _same_ data structure at once is surely not guaranteed, but read the precise definition of "thread-safe" in POSIX. – Ulrich Eckhardt May 05 '20 at 06:14
-
@UlrichEckhardt "A thread-safe function is one that can be safely (i.e., it will deliver the same results regardless of whether it is) called from multiple threads at the same time." - so POSIX documentation consider calling `sendto` from different threads without program corruption, even if it operates on the same data structure. `select` will operate on receivers attributes, which makes it even safer. – Nabuchodonozor May 05 '20 at 06:36
-
How about `shutdown()`, `close()` or `free()`, are those thread-safe as well? By your reasoning, if `free()` is thread-safe, you could call it with the same pointer from different threads. The difference is that the functions themselves are thread-safe, but you still can break stuff by using the same resource (represented by function arguments) from multiple threads. – Ulrich Eckhardt May 05 '20 at 08:45
-
@UlrichEckhardt We were talking about `select` and `sendto`, not other functions which obviously can make a big mess. Scenario with `close` is even documented https://linux.die.net/man/2/select "If a file descriptor being monitored by select() is closed in another thread, the result is unspecified. ... On Linux (and some other systems), closing the file descriptor in another thread has no effect on select(). In summary, any application that relies on a particular behavior in this scenario must be considered buggy. ". `free` also documents MT usage. – Nabuchodonozor May 05 '20 at 08:54
-
I believe that your interpretation of the language used in POSIX is flawed. The reason I brought up `free()` was that it's also specified in POSIX and that similar use of `free()` is obviously buggy to give you an example of your flawed reasoning. – Ulrich Eckhardt May 05 '20 at 09:59
-
@UlrichEckhardt I know what you mean - the argument that two functions are marked as MT-safe doesn't imply that their multithreading usage are in any case correct - I agree with you. But in scenario considered in this question in my opinion it is enough to say it's correct. There are two things here - synchronizing internal structures (indexed by fd) and synchronizing user data (file descriptor or pointer itself). As far as I understood the first one is guaranteed to be safe by POSIX. Synchronization of the second one is up to user - that is why freeing pointer in 2 threads is not safe. – Nabuchodonozor May 05 '20 at 10:31
From my point of view, there shouldn't be any issues when calling sendto
from another thread.
"main thread is blocked on select()"
It means only that it is a blocking call - it does not imply that it blocks others from accessing this resource (socket in this case).

- 154
- 7
You can, but it looks like a weird design.
You can.
Both
select
andsendto
act on sockets, and sockets can be shared among threads or even processes, provided you synchronize them, or use one for reading and one for writing. The only risk if you mix writing or reading on 2 threads is to get only partial data (the other thread getting the other part) or produce garbage because written data is mixed. If one thread usesselect
for reading and the other useswrite
,send
orsendto
forwriting
I cannot see any problemMay be you should not.
Threads and select are 2 ways for achieving the same goal: process different communication channels in the same process. When threading, the common way is to dedicate one thread on each channel and have the threading library or the OS allocate processor time to each thread when it has something to do, as if all the threads executed simultaneously. It leads to simple programs where you code one task at a time.
The
select
system call was created to have one central point that is informed on what communication channel needs action and then explicitely processes it. That way you have one single waiting point that is expected to trigger short operations. You manually decide what shall be done at what moment and can be sure to never be blocked except on theselect
call. It leads to very efficient code (no context change overhead) at the price of being more complex to write because you only code small actions instead of a whole task.Normally, if you go on the
select
way, you should only use threads for long computation asynchronous tasks, but not for IO related ones. That is the reason why I think that your current design is weird.

- 143,923
- 11
- 122
- 252