2

マルチスレッド アプリケーションを作成する必要があるため、最近、非同期プログラミングについてよく読んでいます。

残念ながら、新しく獲得した知識を 1 つのまとまりのある有用な単位にまとめることはできないようです。

私は誰かが私に以下を構築する方法についていくつかの指針を与えることができることを願っています:

  • 指定された順序で多くの異なる (そして時間のかかる) タスクを実行するクラスがあります。

  • 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 に答える