Yes, I said it! Even though the entire point of Peek is to be non-blocking, there is a certain case under which Peek will block. Of course I am talking about the .NET Framework, and I am using version 1.1 from Microsoft. I should really try this same situation under Mono.
What lead me to make this statement so boldly is taking a look at the Rotor source code. Now I realize that Rotor is not what MS uses, but I figured it is good enough to give me some insight.
It turns out that if the stream is empty, that is, it is never streamed anything (haha, that sounds funny), then the Peek function will block. It is obvious from the Rotor source when looking at the implementation of Peek. A stream starts off in a non-blocked status. The charPos and charLen are both zero. They correspond to how much of the stream has been read by the SteamReader consumer, and how much has been buffered by the StreamReader itself. These start off equal, so the implementation of Peek calls a Read. Of course there is nothing to read, so the Read function blocks. This results in Peek being equivalent to a Read on the first (or zeroth? if nothing is ever read) byte read in terms of blocking.
How did I run into this? Well, I’m reading from StandardOutput and StandardError as created by a System.Diagnostics.Process. If a command runs successfully, it usually doesn’t output anything on stderr. The catch is that stderr cannot be ignored. If there is data to read on stderr, it will block stdout, and visa versa, so both streams must be read. What is worse is that if you start reading both streams, stderr blocks immediately. The solution??? Spawn threads to read each, and abort the thread which is blocked on the read from stderr.
If anyone has a better solution, I could really use it. Right now I’m limited to using a time out to trigger the abort on my threads. I’d rather have something which ends sooner.