Ayende @ Rahien

It's a girl

Challenge: Find the bug fix

Usually I tend to pose bugs as the challenges, and not the bug fixes, but this is an interesting one. Take a look at the following code:

var handles = new List<WaitHandle>();
using (
	var stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None, 0x1000,
								 FileOptions.Asynchronous))
{
	for (int i = 0; i < 64; i++)
	{
		var handle = new ManualResetEvent(false);
		var bytes = Encoding.UTF8.GetBytes( i + Environment.NewLine);
		stream.BeginWrite(bytes, 0, bytes.Length, delegate(IAsyncResult ar)
		{
			stream.EndWrite(ar);
			handle.Set();
		}, stream);
		handles.Add(handle);
	}
	WaitHandle.WaitAll(handles.ToArray());
	stream.Flush();

}

Now, tell me why I am creating a ManualResetEvent manually, instead of using the one that BeginWrite IAsyncResult will return?

Comments

Jo&#227;o Bragan&#231;a
07/26/2008 08:16 PM by
João Bragança

Is it because there are not enough ThreadPool threads (i think it defaults to 25 per cpu)?

Ayende Rahien
07/26/2008 08:18 PM by
Ayende Rahien

No, that is not an issue, they will simply execute in batches of 25

Scott MacLellan
07/26/2008 09:14 PM by
Scott MacLellan

Is it because of the order in which their event fires? For example, it will fire prior to the end actually occuring. It could also be that their reset event is configured differently than the one you are making, i.e. maybe their reset event is actually and AutoResentEvent.

Ayende Rahien
07/26/2008 09:17 PM by
Ayende Rahien

There is relation to ordering, but not in the way you are thinking about it

Thomas Krause
07/27/2008 12:23 AM by
Thomas Krause

stream.EndWrite() probably disposes the WaitHandle which causes WaitAll to fail.

Ayende Rahien
07/27/2008 01:13 AM by
Ayende Rahien

Thomas,

Exactly.

But to make matters worse, it will only happen in async mode!

C.J. Anderson
07/27/2008 01:20 AM by
C.J. Anderson

Very subtle.

The WaitHandle returned by IAsyncResult from the async write only "needs" to live until EndWrite is called. Calling WaitAll can potentially throw an ObjectDisposedException if the handle is closed.

The calling set on the manually created handle does not release the handle for GC.

C.J. Anderson
07/27/2008 01:35 AM by
C.J. Anderson

oops. someone got a correct answer in before I posted. mea culpa.

Comments have been closed on this topic.