0

GetList と呼ばれる 2 方向のメソッドと、1 方向のコールバック メソッド ItemUpdated を備えた WCF 二重サービスがあります。

次の状況でデッドロックを検出しました。

  1. サービスは、メソッド OnItemUpdated によってクライアントで処理される ItemUpdated コールバックを呼び出します。
  2. 前のメソッドが戻る前に、何らかのユーザー操作により、クライアントはサービスで GetList を呼び出します。

サービスの ConcurrencyMode を Reentrant に設定できましたが、それは必要ありません。GetList を呼び出す前に、クライアントがサービスからのコールバックを処理していないことを確認する必要があります。

したがって、これが起こらないことを確認するために、オブジェクトを同期させることができます。それは私のより良い選択肢ですか?

アップデート:

私の現在の設計が何であるかを明確にするために、私のサービスは実際には、スケジュールに従ってオブジェクトのリストに対して何らかの処理を行う Windows サービスであり、各アイテムが更新されると、ItemUpdated イベントが発生します。このサービスには、1 つまたは複数のコンソール (クライアント) がそのイベントをサブスクライブし、サービスで何が起こっているかを確認できる WCF サービス ファサードがあります。

4

2 に答える 2

2

InstanceContextMode = Single と共に ConcurrencyMode = Single を使用すると、WCF は単一インスタンスへのすべての呼び出しをシリアル化します。つまり、WCF はシリアル化を強制するためにロックを作成しました。これがデッドロックの原因です。さらに別のロックを追加するとうまくいくかもしれません。しかし、あなたはクライアントロックを提案しています...サービスがデッドロックしないようにするために、クライアントはスレッド動作を変更する必要はありません。サービスはそれよりも堅牢である必要があります

これはサービスの問題です。より堅牢なサービスを作成する必要があります。

サービスを変更してシリアル化を削除し、デッドロックの可能性を完全に防ぐことをお勧めします。私の提案(私が試すために):

  1. サービスの InstanceContextMode を PerCall に変更します。「推奨される」設計は、サービスをステートレスにすることです。呼び出しごとに異なるサービス インスタンスを作成すると、強制的なシリアル化が削除されます。すべての状態情報を共通のストア (データベースやキャッシュなど) に保存します。

  2. サービスに、別のスレッドで ItemUpdated コールバックを作成させます。これにより、コールバックが完了する前にサービス スレッドを完了できます。このソリューションの問題点は、ItemUpdated コールバックが例外をスローした場合、サービスがそれをキャッチして処理するのを待機していないことです。これは、適切なエラー処理がより困難であることを意味します。

詳細については、「 WCF アプリを開発するための強力なインスタンス管理手法の発見」を参照してください。

于 2012-08-30T21:23:27.027 に答える
0

問題は実際にはサービスではなく、クライアントのコールバック ハンドラーにありました。これは基本的に何が起こっていたかです:

  1. 私のサービスは、クライアントで ItemUpdated を呼び出すイベントを発生させます。
  2. コールバックがまだ ItemUpdated を処理している間に、ユーザーは強制的に GetList を実行します。
  3. サービスはリクエストを受け取り、GetList の結果を返しますが、クライアントは別のコールバックを処理しているため、サービスからのレスポンスを処理できません。

そのため、CallbackBehavior 属性を使用して、コールバックで ConcurrencyMode を変更することになりました。サービスは ConcurrencyMode = Single のままです。

于 2012-08-31T13:58:09.370 に答える