5

C# で記述された Windows サービスがあります。サービスは、これを行うスレッドを生成します。

private void ThreadWorkerFunction()
{
  while(false == _stop) // stop flag set by other thread
  {
    try
    {
      openConnection();

      doStuff();

      closeConnection();
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      Thread.Sleep(TimeSpan.FromMinutes(10));
    }
  }
}

データベースがなくなって数回後に Thread.Sleep を入れ、データベース接続エラーでいっぱいの 3Gb ログ ファイルに戻ってきました。

これは何ヶ月も正常に動作していますが、最近、log.Error() ステートメントが「System.InvalidOperationException: This SqlTransaction has completed; it is no longer available」という例外をログに記録し、その後二度と戻ってこないというインスタンスをいくつか確認しました。 . サービスは何日も実行し続けることができますが、それ以上はログに記録されません。

いくつか読んだことで、Thread.Sleep が理想的ではないことはわかっていますが、なぜ元に戻らないのでしょうか?

4

8 に答える 8

5

掘り下げて調べますか?あのろくでなしにデバッガーを貼り付ける !

少なくとも次の可能性が見えます。

  1. ロギング システムがハングします。
  2. スレッドは正常に終了しましたが、他の部分に論理エラーがあるため、サービスはまだ実行されています。

そしておそらく、しかしほぼ間違いなく、次のようなものです:

  • Sleep() がハングします。

ただし、いずれにせよ、デバッガをアタッチすると、スレッドがまだ存在するかどうか、および実際にハングしたかどうかが表示されます。

于 2008-08-27T11:29:58.797 に答える
3

データベースがなくなって数回後に Thread.Sleep を入れ、データベース接続エラーでいっぱいの 3Gb ログ ファイルに戻ってきました。

ロギング システムが重複をトラップするようにして、「前のメッセージは N 回繰り返されました」のようなものを書き込めるようにする方がよいと思います。

可能性のある最後の瞬間に接続を開き、可能な限り早い機会に接続を閉じる方法についての標準的なメモを書いたとします。あなたのデモコードとあなたのアプリケーションは実際に適切に書かれています)。

あなたが説明したエラーを報告していると言うとき、このハンドラーがエラーを報告しているということですか? 私にははっきりしない理由は、コード スニペットで「問題が発生しました」と言っているが、説明ではそれを言っていないからです。例外がどこか別の場所でキャッチされ、コードがスリープ以外の場所で動かなくなっているので、これがそれほどばかげたものになることは望ましくありません。

于 2008-08-27T10:10:32.513 に答える
2

私はまったく同じ問題を抱えていました。スリープラインを例外ハンドラーの外に移動すると、次のように問題が修正されました。

bool hadError = false;
try {
  ...
} catch (...) {
  hadError = true;
}
if (hadError)
  Thread.Sleep(...);

スレッドの中断は、例外ハンドラーのコンテキストでは機能しないようです。

于 2010-07-05T09:59:50.310 に答える
0

Thread.Sleep(10 * 60 * 1000)を試してください

于 2008-08-27T12:28:00.623 に答える
0

何が起こっているのか完全には理解できませんでしたが、10 分間のスリープ中に ThreadInterruptedExceptions がスローされたことに関連しているようだったので、コードを次のように変更しました。

private void ThreadWorkerFunction()
{
  DateTime? timeout = null;

  while (!_stop)
  {
    try
    {
      if (timeout == null || timeout < DateTime.Now)
      {
        openDatabaseConnections();

        doStuff();

        closeDatabaseConnections();
      }
      else
      {
        Thread.Sleep(1000);
      }
    }
    catch (ThreadInterruptedException tiex)
    {
      log.Error("The worker thread was interrupted... ignoring.", tiex);
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      timeout = DateTime.Now + TimeSpan.FromMinutes(10);
    }
  }
}

ThreadInterruptedException を具体的にキャッチすることは別として、これは、すべてのスリープが try ブロック内で発生するため、より安全に感じられるため、発生した予期しないことはすべてログに記録されます。詳細がわかったら、この回答を更新します。

于 2008-09-22T16:44:35.663 に答える
0

あなたが投稿したコードから、例外がスローされた後、システムが確実に再起動できることは明らかではありません-たとえば、例外が doStuff() から発生した場合、制御フローは(10分間待機した後)に戻りますopenConnection()、closeConnection() を通過することはありません。

しかし、他の人が言ったように、デバッガーを接続して、実際の場所を見つけてください。

于 2008-08-27T12:18:36.123 に答える
0

Monitor.Pulseを使用してみましたか(これを実行する前に、スレッドがスレッド管理を使用していることを確認してください)、スレッドに何かを実行させましたか? それが機能する場合は、スレッド ロジックをもう少し調べる必要があります。

于 2008-08-27T10:09:13.063 に答える