2

我最近一直在阅读很多关于异步编程的内容,因为我需要创建一个多线程应用程序。

不幸的是,我似乎无法将我新获得的知识整合到一个有凝聚力和有用的单元中!

我希望有人能给我一些关于如何构建以下内容的指示:

  • 我有一个类以指定的顺序执行许多不同(且耗时)的任务。

  • 我想在我的 Winforms UI 线程中实例化这个类。例如:

    TaskRunner tr = new TaskRunner();
    
  • 我希望能够调用 BeginAsync() 方法(就像您可以使用许多 .NET 内置对象一样)。例如:

    tr.BeginAsync();
    
  • 当某些事件出现时(用于记录、完成等),我希望我的类回调到我的 UI 线程。

  • 我希望能够取消我的课程的执行。例如:

    tr.CancelAsync();
    

我该如何构建该类的内部结构?我似乎找不到任何关于 SqlCommand 或 WebRequest 内部如何工作的内容。

4

3 回答 3

5

对于此操作,您希望使用基于事件的异步模式(与 IAsyncResult 设计模式相对)。有关详细信息,请参阅 MSDN 文档中标题为“基于事件的异步模式概述”的部分,该部分位于:

http://msdn.microsoft.com/en-us/library/wewwczdw.aspx

于 2009-02-19T19:23:09.153 回答
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);
  }
}

示例取自 Joseph Albahari 的 C# 3.0 in a Nutshell, 3rd Edition;本·阿尔巴哈里

于 2009-02-19T19:18:49.693 回答
0

您还应该考虑具有大量内置功能的BackgroundWorker对象,用于执行时间密集型或幕后流程。

本文有一个很好的教程,概述了整个过程,包括显示进度条。

于 2009-02-19T19:31:05.257 回答