-1

I have an application that handles TCP connections, and when a connection is made, BeginRead is called on the stream to wait for data, and the main thread resumes waiting for new connections.

Under normal circumstances, there will be only a few connections at a time, and so generally the number of worker threads created by BeginRead is not an issue. However, in the theoretical situation that many, many connections exist at the same time, eventually when a new connection is made, the call to BeginRead causes an OutOfMemoryException. I would like to prevent the thread from being created in this situation (or be informed of a better way to wait for data from multiple streams).

What are some decent ways of accomplishing this? All I can think to do is to either

a) only allow a certain number of active connections at a time, or

b) attempt to use something called a MemoryFailPoint. After reading, I think this might be the better option, but how do I know how much memory a call to BeginRead will need to do its thing safely?

Cobalt
  • 938
  • 9
  • 21
  • It is highly likely that TCP connections are bottlenecked on network or bandwidth and highly unlikely they are bottlenecked on CPU; that means you will probably be reducing performance by creating many threads, not increasing it. You should consider [asynchronous sockets](https://msdn.microsoft.com/en-us/library/bbx2eya8(v=vs.110).aspx) or [async/await](https://stackoverflow.com/questions/28008978/), not threads. – Dour High Arch Jun 07 '17 at 18:53
  • I would use async/await, but I'm developing on a compact framework that doesn't support fancy stuff like asynchronous operations – Cobalt Jun 07 '17 at 18:56
  • @DourHighArch and even using BeginRead starts a new worker thread for each connection, and will therefore will run out of memory eventually when there a lot of connections. I need either a way to read multiple streams with the same thread or detect when attempting to read a new connection will fail due to OOM – Cobalt Jun 08 '17 at 16:44
  • Where are you getting the idea that “BeginRead starts a new worker thread for each connection”? The docs do not say this, and that is not what the .NET Framework does. You can start one new thread and have it handle all download threads by specifying a separate callback for each connection. A connection is not a thread. – Dour High Arch Jun 08 '17 at 17:12
  • This question is strange; it's like saying "I'm going to be sending a lot of mail, so I have to hire one secretary per envelope, and that's really expensive..." OK, so then *don't do that*. Hire worker threads to do CPU-bound tasks, not I/O bound tasks. – Eric Lippert Jun 08 '17 at 17:27
  • @DourHighArch From MSDN: _Calling the BeginRead method gives you the ability to receive data within a separate execution thread._ https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.beginread(v=vs.110).aspx Also, I can see them in the debugger. – Cobalt Jun 08 '17 at 17:56
  • @EricLippert I'm not _trying_ to hire worker threads, I'm trying to do asynchronous reads from a stream using `BeginRead` which apparently creates worker threads at a one to one ratio despite IOCP saying that it won't – Cobalt Jun 08 '17 at 18:29

2 Answers2

0

Look at this thread here. It can give you many answers for that.

But you can read your current memory usage of your process like this:

Process currentProcess = Process.GetCurrentProcess();
long memorySize = currentProcess.PrivateMemorySize64;
Dennis Larisch
  • 563
  • 4
  • 19
0

You should be using the thread pool to handle these operations, rather than creating whole new threads for every operation you need to perform. Not only will using a thread pool that can re-use threads greatly remove effort spent creating and tearing down threads (which isn't cheap) but the thread pool will work to ensure that threads are only created when it will be beneficial to do so, and will simply let requests to have work done queue up when adding more threads wouldn't be beneficial.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • I was under the impression that threadpools should not be used for blocking operations such as waiting for IO, which is mainly what the processing threads are doing. Is this not the case? – Cobalt Jun 07 '17 at 19:09
  • @Cobalt Indeed, your question implied that it was handling work sent from a connection, not just waiting for a network operation to complete. Of course, you shouldn't be using new threads *either*, for exactly the same reason that you shouldn't be using the thread pool. It's a pointless waste of resources to have a thread sitting there doing nothing when you have no work for it to do. If you want to do something when some IO operation has finished, make the program asynchronous *and use no threads at all* to do that. – Servy Jun 07 '17 at 19:11
  • @Cobalt Note that "processing TCP connections" implies handling the response from a connection, not waiting for a connection to connect or to receive a response, the former being CPU bound work and the latter being IO bound work. – Servy Jun 07 '17 at 19:12
  • I should have said "waiting for data" rather than "processing". Apologies. And I would prefer to do it with async/await, but I'm developing on a compact framework and async/await are not supported, so I've resorted to waiting for reads with threads. Unless there is some way of doing asynchronous reads from a networkstream on Win CE, CF 3.5 – Cobalt Jun 07 '17 at 19:21
  • @Cobalt I haven't worked with that framework, but I'm quite certain that it'll expose *some* means of performing network operations asynchronously, as it's typically a requirement of code performing network operations. – Servy Jun 07 '17 at 19:23
  • There is beginRead and endRead, but I am confused as to how to read in a loop with these methods. In the callback that calls EndRead, would BeginRead be called over again until the connection is terminated? – Cobalt Jun 07 '17 at 20:30
  • 1
    @Cobalt It's well beyond the scope of this question to explain how to write an asynchronous program. Read some tutorials, experiment a bit on your own, and if you're not able to come up with a solution after doing your due diligence, then consider asking another question on the subject. Note that, if you do end up asking another question, "how do I do this whole thing asynchronously" is going to be Too Broad. – Servy Jun 07 '17 at 20:32
  • Also, using asynchronous methods _still_ starts a worker thread to perform the async task. So I would still have the problem of running out of memory if there are many connections. Which is the main issue I am trying to solve here. – Cobalt Jun 08 '17 at 16:38
  • @Cobalt No, the asynchronous operation *won't* start new threads. The whole *point* of using them is that you *don't need a thread at all*. – Servy Jun 08 '17 at 17:10
  • Breaking in the debugger while waiting for reads shows that each BeginRead has an associated worker thread. Additionally the MSDN documentation states: _Calling the BeginRead method gives you the ability to receive data within a separate execution thread._ https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.beginread(v=vs.110).aspx – Cobalt Jun 08 '17 at 17:55
  • @Cobalt The callback *after the operation has finished* is going to be run in a thread pool thread (where you can do CPU bound work with the results of the operation, which is exactly what my answer covers, as that's what you originally asked about). No thread is used while the network operation is happening. – Servy Jun 08 '17 at 17:58
  • If that is the case, why is it that if I call BeginRead 20 times on different streams and break, there are 20 worker threads visible in the debugger? Are they for callbacks? If BeginRead creates threads for its callback, isn't it semantics to say that it "doesn't create threads"? – Cobalt Jun 08 '17 at 18:10
  • @Cobalt I can't possibly comment on the semantics of code not shown. And again, if you have a new question to ask, then you should be asking a new question. – Servy Jun 08 '17 at 18:12
  • My question for you is, if BeginRead doesn't start threads, _as you claim_, then why does each successive call to BeginRead cause a new worker thread to show up in the debugger? As for the semantics of the code being used, it's .NET functions straight out of the box, which I posted the doc for. My code just calls BeginRead and EndRead as per their example. – Cobalt Jun 08 '17 at 18:21
  • @Cobalt And my answer to your question is that I can't tell you why your code is doing what it is when I don't know what your code is doing. There are correct and incorrect ways to perform an asynchronous operations, and many of those incorrect ways will result in you creating a bunch of threads when you don't need to. If you want to get an answer to that question you'll need to ask a new proper question, including enough information for others to reproduce the behavior you've described, rather than posting a comment on an unrelated answer with incomplete information. – Servy Jun 08 '17 at 18:28
  • Fair enough, and here's a link to a better question, if you want to continue trying to hash this out. Thanks for the discussion. https://stackoverflow.com/questions/44439604/continously-reading-from-multiple-tcp-connections-on-cf/44442610?noredirect=1#comment75883814_44442610 – Cobalt Jun 08 '17 at 18:34
  • I didn't like the question ( it was downvoted as well by someone else but me) – baao Jun 12 '17 at 21:15
  • @baao What didn't you like about the question, and how do you think that made the answer not helpful? – Servy Jun 12 '17 at 21:16
  • Someone else downvoted the question, so by your definition it was a bad question. That's why I downvoted your answer, but it must have been a bad one, by your definition. I removed the downvote, because I think that behaviour is stupid though... – baao Jun 12 '17 at 21:18
  • @baao That someone else downvoted it means that someone else thinks that it's a bad question. I have not defined a "bad question" as a question that has a single downvote. A bad question is a question that attracts low quality answers and inhibits the posting of useful answers. If you honestly think that the question is bad, and feel that the answer isn't helpful (perhaps because of problems in the question) than by all means, downvote both posts. But don't downvote them because someone else thinks that they're bad if you don't personally feel that they're not helpful. – Servy Jun 12 '17 at 21:21
  • Yeah, but that's exactly what I tried to complain against on meta, and you hardly tried to defend! – baao Jun 12 '17 at 21:23
  • @baao You weren't complaining about people downvoting posts because *other* people think they're bad, as you did here. You were complaining about people downvoting answers to bad questions as a result of problems in the question. If you honestly felt that there were major problems with the question, and they resulted in the answer not being helpful, then as I said, you *should* downvote. – Servy Jun 12 '17 at 21:27
  • No I wouldn't do that, because actually I think your answer was helpful, even if I would have downvoted the question – baao Jun 12 '17 at 21:28