Posts Tagged ‘pipes’
Implementing IAsyncResult aka NamedPipeClientStream.BeginConnect
Anybody who is working with asynchronously called methods has probably used IAsyncResult. Well, nobody is really using it, instead you are used to get it as a return-value of some BeginX function and put it back in the corresponding EndX function. …
For my current project, i’m using NamedPipeClientStream to connect to a named pipe server (obviously!). I noticed that it does not support asynchronous connection. As my whole projekt is building on asnychronous techniques, I started to implement it.
Here is the code that I come up with for implementing IAsyncResult
using System;
using System.Threading;
namespace Esskar.Threading
{
public class AsyncExcecuter : IAsyncResult, IDisposable
{
private readonly AsyncCallback m_callback;
private bool m_completed;
private bool m_completedSynchronously;
private ManualResetEvent m_waitHandle = null;
private readonly object m_asyncState;
private readonly object m_syncRoot = new object();
public AsyncExcecuter(AsyncCallback cb, object state)
: this(cb, state, false) { }
public AsyncExcecuter(AsyncCallback cb, object state, bool completed)
{
m_callback = cb;
m_asyncState = state;
m_completed = completed;
m_completedSynchronously = completed;
}
#region IAsyncResult Members
public object AsyncState
{
get { return m_asyncState; }
}
public WaitHandle AsyncWaitHandle
{
get
{
lock (m_syncRoot)
{
if (m_waitHandle == null)
m_waitHandle = new ManualResetEvent(false);
return m_waitHandle;
}
}
}
public bool CompletedSynchronously
{
get { lock (m_syncRoot) { return m_completedSynchronously; } }
private set { lock (m_syncRoot) { m_completedSynchronously = value; } }
}
public bool IsCompleted
{
get { lock (m_syncRoot) { return m_completed; } }
private set { lock (m_syncRoot) { m_completed = value; } }
}
#endregion
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (m_syncRoot)
{
if (m_waitHandle != null)
{
((IDisposable)m_waitHandle).Dispose();
m_waitHandle = null;
}
}
}
}
public void Execute()
{
this.Execute(false);
}
public void Execute(bool synchron)
{
if (!this.IsCompleted)
{
if (!synchron)
{
if (!System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(this.InvokeCallback)))
// ThreadPool at its limit (Thanks to Ianier Munoz)
throw new NotSupportedException("ThreadPool failed to queue work item.");
}
else
{
this.InvokeCallback(null);
}
this.CompletedSynchronously = synchron;
}
}
private void InvokeCallback(object state)
{
if (m_callback != null)
m_callback(this);
lock (m_syncRoot)
{
if(m_waitHandle != null)
m_waitHandle.Set();
}
this.IsCompleted = true;
}
}
}
The code is quite simple, i hope. The class uses a ManualResetEvent and signals it when the operation is completed (: the callback function returned).
Having that i implemented BeginConnect and EndConnect for as an LinQ Extension Methods.
using System;
using System.Linq;
using System.IO.Pipes;
using Esskar.Threading;
namespace Esskar.IO.Pipes
{
public static class NamedPipeClientStreamExtension
{
public static IAsyncResult BeginConnect(this NamedPipeClientStream pipe, AsyncCallback callback, object state)
{
AsyncExcecuter executor = new AsyncExcecuter(callback, state);
executor.Execute();
return executor;
}
public static void EndConnect(this NamedPipeClientStream pipe, IAsyncResult asyncResult)
{
pipe.Connect();
}
}
}
Done. Quite easy, isn’t it?