2

I'm writing a server in C#. The asynchronous example on msdn.microsoft.com suggests the following.

  1. BeginAccept to listen for client (& start a new thread when client calls).
  2. BeginReceive to receive the data from client ( & start a new thread to do it on).
  3. BeginSend to reply to send data to client ( & start yet another thread to it on).

At this point there seems to be 4 separate threads, when from my (possibly naive) point of view there really only needs to be 2. 1 for the server to keep listening on and 1 for the conversation with the client. Why does my conversation with the client need 3 threads since I have to wait for a reply before I send and I won't be doing anything else while waiting to receive data from the client?

Cheers

ShanieMoonlight
  • 1,623
  • 3
  • 17
  • 28

2 Answers2

2

BeginAccept does not start a new thread. It is attaching a handler to an OS level hook. No thread is going to be doing the meat of the work for this operation. The same is true for BeginReceive and BeginSend. None of these are starting new threads.

When the events that they are adding handlers for actually fire, then a thread pool thread is created to respond to the action happening. The CPU bound work done here should generally be quite low. What you'll see here is a lot of thread pool threads requested, but very little work being done by them, so they are sent back to the pool very quickly.

The thread pool is designed for this type of use. Rather than creating full threads for each event response (which would be expensive) you can create just 1-2 threads and continually re-use them to respond to all of these events in turn. The pool will only create as many threads as it needs to keep up with a sufficiently small backlog.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • Thanks for the reply @Servy. I know that the Begin***'s don't start the threads until the events fire. I still don't see how it's better to use many threads from the pool for the client conversation when the order of things must be sequentially: Accept wait..., Receive wait..., Reply wait..., Receive wait... etc. (i.e. the program work if I don't wait for each segment to finish before moving to the next)? Cheers. – ShanieMoonlight Jan 15 '14 at 16:43
  • @Shanie Well, the alternative is to have a thread sitting there doing nothing while the operations all take place. You'll have 1 thread spending the vast majority of it's time sitting there doing nothing. Because of that, you'd actually need to have several threads doing this (sitting around doing nothing) just to keep up with the workload. A single thread pool thread, given that it only needs to be "occupied" when there is real CPU bound work to do, can actually process requests much faster. – Servy Jan 15 '14 at 16:53
  • That makes sense @Servy. It seems I need to study the thread pooling a bit more. Thanks for your help. – ShanieMoonlight Jan 15 '14 at 17:04
1

While your main thread will be marshalled around these operations, you should not have to "start a thread" yourself. BeginAccept is a non blocking method - .NET will return immediately from it but invoke your callback on the thread pool when it fulfils its purpose asynchronously. The threadpool is optimised outside of your control.

Drew R
  • 2,988
  • 3
  • 19
  • 27