2016-10-07 2 views
2

非同期APIが同期作る:私はこのように定義されたいくつかのデータを取得するためにAPIに接続してい

クライアントオブジェクトClientConnection、1が要求を送信することができます。 コールバックを受信するためにClientConnectionに渡す必要があるIApiインターフェイス。 を模式的にそれは次のようになります。requestidで、グローバルオブジェクトを介して要求を送信し、そのrequestidでタグ付けされた答えを受ける:

// defined in the API dll 
public class ClientConnection { 
    public ClientConnection(IApi api) { ... } 
    public void request(int reqid, string reqdetails) { ... } 
} 

interface IApi 
{ 
    void receiveData(int reqid, string ans); 
} 

は今、明らかにこれは物事のかなり標準的な非同期的な方法です。

同期しているラッパーを作成したいとします。これを行う最も自然な方法は何でしょうか?スレッド同期やスレッドを使用する代わりに、非同期待機を使用するスマートな方法はありますか?

class MyWrapper : IApi 
{ 
    private ClientConnection _client; 
    private int _reqToken = 0; 
    public MyWrapper() 
    { 
     _client = new ClientConnection(this); 
    } 

    public string getData(string reqdetails) 
    { 
     _client.request(_reqToken++, reqdetails); 
     // what to do here? 
    } 

    public void receiveData(int reqid, string data) { 
     // what to do here? 
    } 
} 

答えて

1

以下のコードはテストしませんでしたが、それはあなたには分かりません。あなたの結果を受信したとき基本的には、通知することManualResetEventを使用することができます(これまで適切なタイムアウトなしでこれを呼び出すことはありません):あなたはそれが仕事をしたりしなかった場合、私に教えてください:)歓迎されている

class MyWrapper : IApi { 
     private ClientConnection _client; 
     // here you store your requests 
     private Dictionary<int, PendingRequest> _pendingRequests = new Dictionary<int, PendingRequest>(); 
     private int _reqToken = 0; 

     public MyWrapper() { 
      _client = new ClientConnection(this); 
     } 

     public string getData(string reqdetails, TimeSpan timout) { 
      // if this is multithreaded - lock over _pendingRequests when you add\remove requests there 
      // and when you increment your _reqToken, or use concurrent collection 
      using (var token = new PendingRequest()) { 
       var id = _reqToken; 
       // lock here 
       _pendingRequests.Add(id, token); 
       _client.request(id, reqdetails); 
       // and here use Interlocked.Increment 
       _reqToken++; 
       if (!token.Signal.WaitOne(timout)) { 
        // and here 
        _pendingRequests.Remove(id); 
        // timeout 
        throw new Exception("timout"); 
       } 
       // if we are here - we have the result 
       return token.Result; 
      } 
     } 

     public void receiveData(int reqid, string data) { 
      // here you might need to lock too 
      if (_pendingRequests.ContainsKey(reqid)) {      
       var token = _pendingRequests[reqid]; 
       _pendingRequests.Remove(reqid); 
       token.Complete(data); 
      } 
     } 

     private class PendingRequest : IDisposable { 
      public PendingRequest() { 
       Signal = new ManualResetEvent(false); 
      } 

      public ManualResetEvent Signal { get; private set; } 

      public string Result { get; private set; } 

      public void Complete(string result) { 
       this.Result = result; 
       Signal.Set(); 
      } 

      public void Dispose() { 
       Signal.Dispose(); 
      } 
     } 
    } 
+0

をいくつかのバグが含まれてい、私は答えを修正することができるように – Evk

関連する問題