Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3562
  • Last Modified:

C# .NET Stream.BeginRead() is blocking, not parallel thread

I am using C#.NET 1.1, however it would appear that my problem may be with any release of the .NET Famework (so, 2.0 also, as I think 3.0 and 3.5 use the same base library as 2.0).

My problem is that when I issue a simple BeginRead() off of a Stream variable (in System.IO), the method blocks until the entire file is read.  The arguments for BeginRead are in the code block below.  I pass in my byte[] buffer, an offset of 0, the length of my buffer, my callback method, and in this case I'm using null for object state, which is perfectly valid.    It _does_ read, so it works, it just doesn't continue on as it's supposed to.

If I call BeginRead off my Stream var and then immediately issue a Console.WriteLine("This line right after BeginRead call!!"), I don''t receive the Console.WriteLine until -after- the entire read process has completed.  I've tried this with changing the size of the byte buffer and the size of the file, I've even put the file on an external drive and given a buffer length of like 1 but to no avail.  Actually with a large file (~200MB) and a byte buffer length of 1 I get a Fatal Stack Overflow error and the program throws.

Simple C# program.  Ideas?  Am I misunderstanding the idea of BeginRead's state object here, or what is going on?  I've done a bit of digging and this does appear to be the appropriate use.  Also I've encountered training documentation which says not only that this is the way to do it but also that until you issue an EndRead(), you won't get a block (EndRead() apparently blocks until the file is done reading, but I wouldn't know as my BeginRead() is blocking).  One other interesting thing to note is that I get multiple calls to my callback method.  Help!

// Signature for BeginRead()
public virtual IAsyncResult BeginRead(
   byte[] buffer,
   int offset,
   int count,
   AsyncCallback callback,
   object state

Open in new window

  • 3
  • 2
1 Solution
OK.. First.. where to you put the line EndRead ? It should be in your callback method. Isn't it ? If so, you should set a buffer around 4000, which tells the reader to read 4000 bytes at a time.

So, if you have a file of 40000 bytes, your callback method will be called with a 4000 bytes array (the first ones). The callback method shall have the EndRead as first call into the method. Then looking if the buffer return is not empty, you call again the BeginRead, or if it is, you exit the method.

So, you will have to combines to bytes into a Collection, and when finished, you will have to whole file read. This should gives you an Asynchronous way to read the file. Although, I never read a file asynchronously, I just use this with NetworkStream, it should work. If not, give me the code where all BeginRead and EndRead are located. (The whole methods).
coder1313514512456Author Commented:
Sure.  Since it's pretty compact, here it is:

// aioee.cs - Testing Asynchronous I/O  -  EE ask version
using System;
using System.IO;
using System.Text;
using System.Threading;
namespace AIOEE
	public class AsyncTest
		// private const int bufferSize = 10;           // to try to slow it down
		private const int bufferSize = 256;             // arbitrary
		// private const int bufferSize = 4000;         // suggested by djon2003
		// private const int bufferSize = 1000000000;   // fast, of course
		private const string inputFileName = "somefile.txt";
		private byte[] buffer;
		private Stream inStream;
		private AsyncCallback callbackMethod;
		public AsyncTest()
			inStream = File.OpenRead(inputFileName);
			buffer = new byte[bufferSize];
			callbackMethod = new AsyncCallback(this.OnCompletedRead);
		}  // end AsyncTest()  ctor
		public static void Main(string[] args)
			AsyncTest tester = new AsyncTest();
		} // end Main()
		public void Run(string[] args)
			// using null instead of a local state object
			inStream.BeginRead(buffer, 0, buffer.Length, callbackMethod, null);
			Console.WriteLine("Run():  Immediately following BeginRead() call.");
			// do some token work in between to prove that we're asynchronous.
			// Note that this never shows up until the end regardless of file/buffer sizes,
			// which means the BeginRead() is blocking.
			for (long i=0; i<=100000; i++)
				if (i%1000 == 0)
					Console.WriteLine("i:  {0}", i);
				}  // end if
			}  // end for
		} // end Run()
		// Callback method.
		void OnCompletedRead(IAsyncResult asyncResult)
			Console.WriteLine("HIT ONCOMPLETEDREAD Method.");
			int bytesRead = inStream.EndRead(asyncResult);
			if (bytesRead == 0)
				Console.WriteLine("OnCompletedRead():  No bytes read -- must be done");
				string s = Encoding.ASCII.GetString(buffer, 0, bytesRead);
				// my this could get large
				// Console.WriteLine(s);
				// If bytes have been read, try to read more
				// Is this why I'm blocking?
				// Is this also why I'm bombing on large files with small buffer sizes?
				inStream.BeginRead(buffer, 0, buffer.Length, callbackMethod, null);
			}  // end if-else
		}  // end OnCompletedRead()
	}  // end class AsyncTest
} // end namespace AIOEE

Open in new window

coder1313514512456Author Commented:
Oh, and correction to Run() method:

void Run()
   // ...

Open in new window

coder1313514512456Author Commented:
Solved it -- it's because I was using 1.1 insted of 2.0.
This was a problem in 1.1 and I totally forgot about it.
I am such an idiot!  Thanks for the help.
Good thing you find your way !

Featured Post

Veeam and MySQL: How to Perform Backup & Recovery

MySQL and the MariaDB variant are among the most used databases in Linux environments, and many critical applications support their data on them. Watch this recorded webinar to find out how Veeam Backup & Replication allows you to get consistent backups of MySQL databases.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now