2009-02-19 67 views
2

最近我一直在閱讀很多有關異步編程的內容,因爲我需要創建一個多線程應用程序。如何創建一個具有異步功能的類(類似於SqlCommand或WebRequest)?

不幸的是,我似乎無法將我最近獲得的知識整合到一個凝聚力和有用的單位!

我希望有人可以給我如何構建以下一些要點:

  • 我有一個類,做了很多不同的(耗時)的任務在指定的序列。

  • 我想在我的Winforms UI線程中實例化這個類。例如:

    TaskRunner tr = new TaskRunner(); 
    
  • 我希望能夠調用一個BeginAsync()方法(你可以有很多的.NET內置對象做)。例如:

    tr.BeginAsync(); 
    
  • 我想我的課回調到我的UI線程當某些事件發生(有關記錄,竣工等)。

  • 我希望能夠取消我班的執行。例如:

    tr.CancelAsync(); 
    

如何去構建一個類的內部?我似乎無法找到任何有關SqlCommand或WebRequest的內部結構如何工作的內容。

回答

1

希望這個例子能幫助你。

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); 
    } 
} 

實施例是從C#3.0果殼中由Joseph阿爾巴哈利採取,第3版 ; Ben Albahari

+0

謝謝,這有點讓我心動,但我會繼續研究它。 – James 2009-02-19 19:21:56

+0

@Valentin Vasiliev:不幸的是,這不是他正在尋找的模式。他正在尋找基於事件的異步模式。 – casperOne 2009-02-19 19:23:48

+0

基於事件的異步模式通常比較簡單,所以我希望他能處理更簡單的問題:-) – Valentin 2009-02-20 05:54:37

0

你也應該考慮到有很多內置該功能BackgroundWorker對象時間緊迫或幕後流程。

This article有一個很好的教程概述了整個過程,包括顯示進度條。

相關問題