15

私が今知っていることの簡単な要約

作成してEventWaitHandle閉じた があります。この ctorで再作成しようとすると、「パスへのアクセス ... が拒否されました」という例外がスローされます。この例外はまれであり、ほとんどの場合、問題なく再作成されますEventWaitHandle。以下に(私が)投稿した回答を使用するEventWaitHandle.OpenExistingと、例外がスローされた場合でも正常に呼び出して続行できますが、ctor はEventWaitHandle私のためにこれを行うべきでしたよね? それがout パラメータ,createdNewの目的ではありませんか?


最初の質問

同じサーバー上に次のアーキテクチャ、Windows サービス、および Web サービスがあります。Web サービスは、Windows サービスが待機している待機ハンドルを開いて設定することにより、作業を行う必要があることを Windows サービスに伝えます。

通常、すべてに問題はなく、問題が発生することなく Windows サービスを開始/停止できます。ただし、Web サービスを停止してから再起動すると、待機ハンドルを完全に作成できず、アーキテクチャ全体が壊れてしまうことがあります。

特に、何がイベント待機ハンドルを壊しているのかを突き止めて停止する必要があります。待機ハンドルが「壊れた」場合、ウィンドウが再び適切に機能する前にウィンドウを再起動する必要がありますが、これは明らかに理想的ではありません。

更新: スローされた例外と問題のログ

問題を引き起こすことを期待して、Web サービスが動作している間に Windows サービスを再起動しました。一部のクラス名は、企業の匿名性のために検閲されています

12:00:41,250 [7] - Stopping execution due to a ThreadAbortException
System.Threading.ThreadAbortException: Thread was being aborted.
   at System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)
   at OurCompany.OurProduct.MyClass.MyClassCore.MonitorRequests()

12:00:41,328 [7] - Closing Event Wait Handle
12:00:41,328 [7] - Finally block reached


12:00:42,781 [6] - Application Start
12:00:43,031 [6] - Creating EventWaitHandle: Global\OurCompany.OurProduct.MyClass.EventWaitHandle
12:00:43,031 [6] - Creating EventWaitHandle with the security entity name of : Everyone

12:00:43,078 [6] - Unhandled Exception 
System.UnauthorizedAccessException: Access to the path 'Global\OurCompany.OurProduct.MyClass.EventWaitHandle' is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.Threading.EventWaitHandle..ctor(Boolean initialState, EventResetMode mode, String name, Boolean& createdNew, EventWaitHandleSecurity eventSecurity)
   at OurCompany.OurProduct.MyClassLibrary.EventWaitHandleFactory.GetNewWaitHandle(String handleName, String securityEntityName, Boolean& created)
   at OurCompany.OurProduct.MyClassLibrary.EventWaitHandleFactory.GetNewEventWaitHandle()
   at OurCompany.OurProduct.MyClass.MyClassCore..ctor()

大まかなタイムライン:

  • 11:53:09,937: Web サービスの最後のスレッドが既存の待機ハンドルを開き、その作業を完了しました (クライアントとの接続が終了した場合と同様)。

  • 12:00:30,234: Web サービスは新しい接続を取得しますが、まだ待機ハンドルを使用していません。この接続のスレッド ID は、11:53 の最後の接続のスレッド ID と同じです。

  • 12:00:41,250: Windows サービスが停止します

  • 12:00:42,781: Windows サービスが起動します

  • 12:00:43,078: Windows サービスのクラッシュが終了しました

  • 12:00:50,234: Web サービスは実際に待機ハンドル呼び出し Set() を開くことができましたが、例外がスローされることはありませんでした。

  • 12:02:00,000: Windows サービスを再起動しようとしましたが、同じ例外が発生しました

  • 12:36:57,328: 任意に 36 分間待った後、システムを完全に再起動することなく、Windows サービスを開始することができました。


Windows サービス コード

初期化:

// I ran into security issues so I open the global EWH
//    and grant access to Everyone
var ewhSecurity = new EventWaitHandleSecurity();

ewhSecurity.AddAccessRule(
 new EventWaitHandleAccessRule(
  "Everyone",
  EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify,
  AccessControlType.Allow));

this.ewh = new EventWaitHandle(
 false,
 EventResetMode.AutoReset,
 @"Global\OurCompany.OurProduct.MyClass.EventWaitHandle",
 out created,
 ewhSecurity);

// the variable "created" is logged

利用:

// wait until the web service tells us to loop again
this.ewh.WaitOne();

廃棄/閉鎖:

try
{
    while (true)
    {
        // entire service logic here
    }
}
catch (Exception e)
{
    // should this be in a finally, instead?
    if (this.ewh != null)
    {
        this.ewh.Close();
    }
}

Web サービス コード

初期化:

// NOTE: the wait handle is a member variable on the web service
this.existing_ewh = EventWaitHandle.OpenExisting(
    @"Global\OurCompany.OurProduct.MyClass.EventWaitHandle");

利用:

// wake up the windows service
this.existing_ewh.Set();

は Web サービスのメンバー変数であるためEventWaitHandle、具体的に閉じるコードはありません。実際、EventWaitHandleオン ザ Web サービスと対話する唯一のコードは上に掲載されています。


振り返ってみるとClose()catchブロック内にある をブロック内に置くべきだったのかもしれませんfinally。おそらく Web サービスに対しても同じことを行うべきだったのですが、それが必要だとは思いませんでした。

いずれにせよ、私が特に間違ったことをしているかどうかは誰にもわかりますか? close ステートメントを finally ブロック内に配置することは非常に重要ですか? Web サービスClose()のを手動で制御する必要がありますか?existing_ewh

また、これはやや複雑な問題であることは承知しています。追加情報が必要な場合はお知らせください。詳しく監視し、必要な情報や説明を追加します。

参考資料

4

2 に答える 2

12

Windows サービスで待機ハンドルを作成するコードで、失敗した場合 (アクセスが拒否された場合など)、次の方法で「既存の待機ハンドルを開く」ことを試みることができます。

EventWaitHandle.OpenExisting(
    @"Global\OurCompany.OurProduct.MyClass.EventWaitHandle",
    EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify);

ただし、その時点で動作が同じままであるかどうかは完全にはわかりません。

注: フィードバックをいただければ幸いです。それは潜在的な答えなので、私は自分の質問に答えています。繰り返しますが、たくさんのコメントは大歓迎です!

注 2: 驚くべきことEventWaitHandleRights.FullControlに、上記のフラグ ( Synchronize+ Modify) の代わりに適用するとうまくいきません。上記のサンプルを使用する必要があります。

于 2009-11-24T17:43:41.387 に答える
1

MSDN は次のように述べています。

UnauthorizedAccessException - 指定されたイベントが存在し、アクセス制御セキュリティが設定されていますが、ユーザーには EventWaitHandleRights.FullControl がありません。

呼び出し元は、eventSecurity が現在のユーザーに一部のアクセス権を拒否または付与できなかった場合でも、新しく作成された EventWaitHandle オブジェクトを完全に制御できます。

サービスには、EventWaitHandle コンストラクターを介して既存のイベントを取得する権限がありません。(EventWaitHandleRights.FullControl は指定されていません。名前付きイベントは、ハンドルが開いている間も存在します。) EventWaitHandle.OpenExisting を使用して、既存のイベントを開くことができます。

于 2009-11-25T07:32:08.577 に答える