I've been reading a lot about asynchronous programming recently, as I need to create a multi-threaded application.
Unfortunately I can't seem to bring my newly acquired knowledge together into one cohesive and useful unit!
I'm hoping someone can give me some pointers on how to construct the following:
I have a class that does a lot of different (and time-consuming) tasks in a specified sequence.
I'd like to instantiate this class in my Winforms UI thread. eg:
TaskRunner tr = new TaskRunner();I'd like to be able to call a BeginAsync() method (as you can do with lots of the .NET built-in objects). eg:
tr.BeginAsync();I'd like my class to callback to my UI thread when certain events arise (for logging, completion etc).
I'd like to be able to cancel the execution of my class. eg:
tr.CancelAsync();
How do I go about building the internals of that class? I can't seem to find anything that talks about how the internals of SqlCommand or WebRequest might work.
-
Hope, this example will help you.
public class MessagingServices { public static IAsyncResult BeginReverseEcho (TcpClient client, AsyncCallback callback, object userState) { var re = new ReverseEcho( ); re.Begin (client, callback, userState); return re; } public static byte[] EndReverseEcho (IAsyncResult r) { return ((ReverseEcho)r).End( ); } } class ReverseEcho : IAsyncResult { volatile TcpClient _client; volatile NetworkStream _stream; volatile object _userState; volatile AsyncCallback _callback; ManualResetEvent _waitHandle = new ManualResetEvent (false); volatile int _bytesRead = 0; byte[] _data = new byte [5000]; volatile Exception _exception; internal ReverseEcho( ) { } // IAsyncResult members: public object AsyncState { get { return _userState; } } public WaitHandle AsyncWaitHandle { get { return _waitHandle; } } public bool CompletedSynchronously { get { return false; } } public bool IsCompleted { get { return _waitHandle.WaitOne (0, false); } } internal void Begin (TcpClient c, AsyncCallback callback, object state) { _client = c; _callback = callback; _userState = state; try { _stream = _client.GetStream( ); Read( ); } catch (Exception ex) { ProcessException (ex); } } internal byte[] End( ) // Wait for completion + rethrow any error. { AsyncWaitHandle.WaitOne( ); AsyncWaitHandle.Close( ); if (_exception != null) throw _exception; return _data; } void Read( ) // This is always called from an exception-handled method { _stream.BeginRead (_data, _bytesRead, _data.Length - _bytesRead, ReadCallback, null); } void ReadCallback (IAsyncResult r) { try { int chunkSize = _stream.EndRead (r); _bytesRead += chunkSize; if (chunkSize > 0 && _bytesRead < _data.Length) { Read( ); // More data to read! return; } Array.Reverse (_data); _stream.BeginWrite (_data, 0, _data.Length, WriteCallback, null); } catch (Exception ex) { ProcessException (ex); } } void WriteCallback (IAsyncResult r) { try { _stream.EndWrite (r); } catch (Exception ex) { ProcessException (ex); return; } Cleanup( ); } void ProcessException (Exception ex) { _exception = ex; // This exception will get rethrown when Cleanup(); // the consumer calls the End( ) method. } void Cleanup( ) { try { if (_stream != null) _stream.Close( ); } catch (Exception ex) { if (_exception != null) _exception = ex; } // Signal that we're done and fire the callback. _waitHandle.Set( ); if (_callback != null) _callback (this); } }Example is taken from C# 3.0 in a Nutshell, 3rd Edition by Joseph Albahari; Ben Albahari
James : Thanks, that's kind of blowing my mind at the moment but I will continue to study it.casperOne : @Valentin Vasiliev: Unfortunately, it's not the pattern he is looking for. He is looking for the event-based async pattern.Valentin Vasiliev : Event-based async patterns are generally simpler, so I hope he'll handle the easier one :-) -
For this operation, you want to use the event-based asynchronous pattern (as opposed to the IAsyncResult design pattern). For more information, see the section of the MSDN documentation titled "Event-based Asynchronous Pattern Overview", located at:
http://msdn.microsoft.com/en-us/library/wewwczdw.aspx
James : Yes, that looks very promising...James : I've been reading through the documentation and that's exactly what I need. Thank you. -
You should also consider the BackgroundWorker object that has a lot of that functionality built in for doing time intensive or behind the scene processes.
This article has a nice tutorial outlining the entire process, including having a progress bar displayed.
James : The BackgroundWorker is useful, and I built half a prototype with it, but it's not quite what I need.
0 comments:
Post a Comment