1

System.Timers.Timer を使用してデータベース接続を ping し、マウントされたファイルの存在をチェックするコードがいくつかあります。タイマーを設定するコードは次のとおりです。

m_Timer = new System.Timers.Timer(TimeSpan.FromSeconds(10).TotalMilliseconds);

m_Timer.Elapsed += (object xiSender, ElapsedEventArgs xiEventArgs) =>
{
    PingRemoteFolder();
    PingDatabase();
};

これは、シングルトン クラスのコンストラクターで発生します。

System.Timers.Timer は、毎回実行しようとしている操作が指定された間隔よりも長くかかる場合、スレッド プールから複数のスレッドを使用することを知っていますが、私たちの状況ではそうではありません。

タイマーのイベントは、10 秒ごとよりもはるかに頻繁に発生しているようで、一度に最大 4 つまたは 5 つのスレッドを使用しています。

何か案は?また、これは、ワーカー スレッドを使用してこのタイマーを使用して値を設定するクラスのプロパティをチェックする WPF アプリケーションのメイン スレッドでスタック破損が発生している別の状況に関連していると考えられます。

Windows 2008R2 上の .NET バージョン 4.0

編集:

また、WPF アプリケーションのメイン スレッドでスタックの破損が発生すると、タイマー イベント ハンドラーが呼び出すメソッドの 1 つで InvalidOperationException がスローされ、「タイムアウトが期限切れになりました。プールから接続を取得する前にタイムアウト期間が経過しました。これは、プールされたすべての接続が使用中で、最大プール サイズに達したために発生した可能性があります。」

PingRemoteFolder() は Directory.GetFiles("somepath") を実行しようとします

PingDatabase():

private void PingDatabase()
{
    if(!string.IsNullOrEmpty(CurrentInstance.Name) && DoPing)
    {
        SqlConnection sqlConnection = null;

        try
        {

            SqlConnectionStringBuilder sqlConnectionStringBuilder = new SqlConnectionStringBuilder();

            sqlConnectionStringBuilder.DataSource = CurrentInstance.Instance;
            sqlConnectionStringBuilder.IntegratedSecurity = CurrentInstance.AuthenticationMode == SmoAuthenticationMode.WindowsAuthentication;
            sqlConnectionStringBuilder.InitialCatalog = CurrentInstance.Name;

            if(CurrentInstance.AuthenticationMode == SmoAuthenticationMode.SqlServerAuthentication)
            {
                sqlConnectionStringBuilder.UserID = CurrentInstance.UserName;
                sqlConnectionStringBuilder.Password = CurrentInstance.Password;
            }

            sqlConnection = new SqlConnection(sqlConnectionStringBuilder.ToString());

            sqlConnection.Open();

            Assert.Condition(sqlConnection.State == ConnectionState.Open, "sqlConnection.State == ConnectionState.Open");

            IsCurrentInstanceReachable = true;

        }
        catch(Exception ex)
        {
            IsCurrentInstanceReachable = false;
            CurrentInstance.Name = string.Empty;
        }
        finally
        {
            if(sqlConnection != null && (sqlConnection.State != ConnectionState.Closed && sqlConnection.State != ConnectionState.Broken))
            {
                SqlConnection.ClearPool(sqlConnection);

                sqlConnection.Close();
                sqlConnection = null;
            }
        }
    }
}
4

1 に答える 1

2

データベースに接続プールの問題があり、タイマー コールバックが PingDatabase() の呼び出しでブロックされているようです。これにより、複数のタイマー コールバック スレッドが同時に存在します。タイマー関数の先頭に m_Timer.Enabled = false の呼び出しを配置し​​、関数の最後に m_Timer.Enabled = true の呼び出しを配置することで、これを簡単に確認できます。これにより、常に 1 つのスレッドのみが存在するようになります。

m_Timer.Elapsed += (object xiSender, ElapsedEventArgs xiEventArgs) =>
{
    m_Timer.Enabled = false;
    PingRemoteFolder();
    PingDatabase();
    m_Timer.Enabled = true;
};
于 2013-04-26T20:58:15.277 に答える