I think everyone should prefer synchronous API relying on your threads instead. For example, a network service typically need just tow thread to work with sockets, let me call them "listening thread" and "application protocol thread". Usually the best TCP API is
TcpListener/TcpClient
. The listening thread is listening for new connections, accepts them and put obtained client sockets (objects representing connected remote sockets on the service host) and put it in some collection shared between threads. The application protocol thread is reading/writing from/to network stream to follow some application-level protocol. A disconnection from either side could be processed to remove an item from the collection, so no graceful disconnection is needed. Of course you need to use appropriate thread synchronization primitives.
Same way, the client part needs a separate thread to work with sockets, just one.
See also my past solution:
using api in c# and socketprogramming[
^].
Franky, I don't know situation where asynchronous APIs could be preferred over custom threads. Threads are easier to program and provide more explicit and fine-grain control. I think asynchronous APIs were offered to developers when threading was not a common place as it is now and now is only useful to support legacy code. No need to use it for new development.
—SA