1

サーバーの1つが稼働していることを確認することを目的とした小さなプログラムを設計しています。場合によっては、サーバーが応答せず、スクリプトを起動してサーバーを再起動する必要があります。

最初に、情報を取得する役割を担う新しいスレッドを開始します。その後、特定の期間、メイン スレッドが参加します。次に、スレッドを中止して切断し、最後にスレッドに参加して、キャッチを実行し、最後にブロックするのに十分な時間を残します。

理論的にはうまくいくはずです: タイムスパンが十分に短い場合、実際にサーバーがダウンしていることを示します (割り当てられた短いタイムスパンで接続を確立できなかったため)。しかし、場合によっては、サーバーが実際にダウンしている場合でも、ThreadAbortException が何の効果もなかったかのように、プログラムは実行を続けます。問題は、これらのダウンタイムが非常に散発的であるため、自分でデバッグして何が正しく機能していないかを確認できなかったことです。

方法は次のとおりです。

これは、ワーカー スレッドを呼び出すメイン スレッドです。非常に簡単です。

public void LaunchCommand()
{
    Thread pingThread = new Thread(new ThreadStart(Ping));
    pingThread.Start();
    while (!pingThread.IsAlive);
    pingThread.Join(new TimeSpan(0, 0, _maxTime)); 
    pingThread.Abort(); //  Time's up.
    pingThread.Join();  //  Make sure we complete everything before moving on
}

呼び出されたスレッドは次のとおりです。

private void Ping()
{
    try
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        serviceType = Type.GetTypeFromProgID(serviceProgID, _server, true);
        service = Activator.CreateInstance(serviceType);
        _xmlResult = ApxServiceType.InvokeMember("ExecuteXML", BindingFlags.InvokeMethod, null, service, new string[] { _dataset, Command, string.Empty }) as string;

        stopwatch.Stop();
        _latency = stopwatch.Elapsed;

        // Trivial validations to make sure _status is true, such as _xmlResult.Contains(certainSubString); and such

        _status = true;     //  Everything seems to work fine if we could make up to here.
    }
    catch (ThreadAbortException)
    {
        Console.WriteLine("Server timeout :(");
        return;
    }
    catch (Exception e)
    {
        Console.WriteLine("Server exception: " + e.Message);
        return;
    }
    finally
    {
        if (!_status)
        {
            _latency = new TimeSpan(0, 0, _maxTime);
        }
    }
}

Commands、serviceProgID などの変数は別の場所で宣言されており、適切に機能することがわかっています。私の問題は、ストップウォッチの宣言/初期化に続く3行に及ぶと思います。まず、同様のアプリケーションからこれらの行をコピーして貼り付けたと言わざるを得ませんが、基本的には、指定されたコマンドから結果のみをフェッチする必要があります。残念ながら危機的状況でデバッグできなかったので、どの行が問題なのかはわかりませんが、とにかく ThreadAbortException は効果がないようです。コードがアンマネージドに切り替えられたためですか?

私はここで迷子になっているので、どんなアイデアでも歓迎します! ありがとう!

4

1 に答える 1

1

実際、シナリオに別のスレッドを使用する必要はありません。同期操作を使用してサーバーの可用性を確認できます。サーバーの可用性を確認するために使用されている機能は、タイムアウト オプションを提供していますか? はいの場合、タイムアウトオプションで十分です。タイムアウト前に関数が返された場合は、サーバーがオンラインであることを意味し、それ以外の場合はサーバーがダウンしています。

サーバーの可用性をチェックする機能でタイムアウト オプションが提供されず、スレッドが永久に (または長時間) 待機する可能性がある場合は、新しいスレッドを使用できます。ただし、Thread.Join(Timeout)メソッドが true を返し、_status変数も true の場合は、サーバーがオンラインであることを確認できます。Thread.Join(Timeout)false を返す場合は、サーバーがダウンしていることを意味します。

良い習慣としてThread.ResetAbort、catch ブロック処理の Abort 例外で使用する必要があります。それ以外の場合、catch ブロックの実行が終了すると、ランタイムは ThreadAbort 例外を再スローします。

于 2012-10-11T16:04:56.623 に答える