2017-04-18 1 views
0

私は、その関数にアクセスするために、DllImportを使用してクラスにラップしたサードパーティのC++ dllへの呼び出しに問題があります。try-catch-finallyブロックを構成して、最終的にエラーを処理するにはどうすればよいですか?

dllは、使用前にセッションが開かれることを要求します。これは、操作を実行するときにそのセッションを参照するために使用される整数ハンドルを返します。終了したら、同じハンドルを使用してセッションを終了する必要があります。だから私はこのような何かをした:

public void DoWork(string input) 
{ 
    int apiHandle = DllWrapper.StartSession(); 

    try 
    { 
     // do work using the apiHandle 
    } 
    catch(ApplicationException ex) 
    { 
     // log the error 
    } 
    finally 
    { 
     DllWrapper.CloseSession(apiHandle); 
    } 
} 

私が持っている問題はCloseSession()は時々、ねじを実行しているときにエラーをスローする問題のDLLを引き起こすことがある:

System.AggregateException:1つ以上のエラーが発生しました。 ---> System.AccessViolationException:保護された メモリを読み書きしようとしました。これはしばしば、他のメモリが壊れていることを示します。

Dllをスレッド方式で使用しているように見えるので、私はこのエラーを停止することができません。スレッドセーフであると思われます。しかし、私のCloseSession()関数は、Dllのクローズ関数を呼び出す以外は何もしないので、何かを "修正"する余裕があまりありません。

しかし、最終的にはセッションが正常に終了しないことになります。だから、プロセスがやり直さなければならないプロセスは、オープンセッションに遭遇し、新しいエラーを投げつけ続けます。そのセッションは絶対にに閉鎖されるを持っています。

エラー処理ステートメントを設計する方法について、私は紛失しています。これは、セッションが常に閉じることを保証するものです。

+4

私は疑問に思うのですが、どのようにエラーを "処理"する必要がありますか?セッションを終了するとサードパーティのコードからエラーが発生し、セッションを終了せずに処理を続けることができない場合は、次に何を行いますか?つまり、 'finally /'の中に別の 'try/catch'を置くことができますが、実際にエラーにどのように反応しますか?サードパーティのツールが動作していない場合、何ができるのですか? – David

+4

これがスレッディングによって発生した場合は、StartSessionを中心に[lock(){}](https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx)ステートメントを使用して問題を回避できます()メソッドとCloseSession()メソッドを呼び出します。 – Serge

+0

@Davidサードパーティのツールが失敗するのは断続的です。もう一度試してみると通常はうまくいきます。私の実際のコードは現在、これが常に起こることを確実にしようとする再帰と制御フローのひどい混乱です。私はもっ​​と嫌いですが、もし私がする必要があれば、私はする必要があります:( –

答えて

1

私は、外部リソースの廃棄を含むようにラッパーを変更し、ハンドルもラップします。私。ハンドルでセッションを表現するのではなく、ラッパーオブジェクトで表現します。

さらに、DLLへの呼び出しをlock-statsements(@ Sergeの示唆)にラップすると、マルチスレッドの問題を完全に防ぐことができます。すべてのDllWrappersが同じロックオブジェクトを使用するように、ロックオブジェクトは静的であることに注意してください。

public class DllWrapper : IDisposable 
{ 
    private static object _lockObject = new object(); 

    private int _apiHandle; 
    private bool _isOpen; 

    public void StartSession() 
    { 
     lock (_lockObject) { 
      _apiHandle = ...; // TODO: open the session 
     } 
     _isOpen = true; 
    } 

    public void CloseSession() 
    { 
     const int MaxTries = 10; 

     for (int i = 0; _isOpen && i < MaxTries; i++) { 
      try { 
       lock (_lockObject) { 
        // TODO: close the session 
       } 
       _isOpen = false; 
      } catch { 
      } 
     } 
    } 

    public void Dispose() 
    { 
     CloseSession(); 
    } 
} 

ここで、メソッドはインスタンスメソッドであることに注意してください。

今、あなたはusingステートメントとのセッションの閉鎖を確保することができます。

using (var session = new DllWrapper()) { 
    try { 
     session.StartSession(); 
     // TODO: work with the session 
    } catch(ApplicationException ex) { 
     // TODO: log the error 
     // This is for exceptions not related to closing the session. If such exceptions 
     // cannot occur, you can drop the try-catch completely. 
    }  
} // Closes the session automatically by calling `Dispose()`. 

あなたはこのクラスSessionとメソッドOpenCloseを呼び出すことによって命名向上させることができます。このクラスのユーザーは、ラッパーであることを知る必要はありません。これは単なる実装の詳細です。また、メソッドの命名は対称的であり、名前Sessionを繰り返す必要はありません。

エラー処理、エラー状況からの回復、リソースの廃棄など、すべてのセッション関連の要素をカプセル化することで、コード内の混乱を大幅に減らすことができます。 Sessionクラスは現在、高度な抽象クラスです。古いDllWrapperは、低レベルと高レベルの中間のどこかにありました。

+0

ありがとうございます。私はあなたが問題を解決し、同時にコードを整理する手段として、どこに行くのが大好きです。この方法を使った最初のプロトタイプは、処理速度が大幅に遅くなったように思えます。調べています - もし私がキンクを打ち消すことができれば、受け入れてうれしいです。 –

関連する問題