System.Timers.定时器,比interval更频繁地运行,使用多个线程

本文关键字:运行 线程 定时器 Timers interval System | 更新日期: 2023-09-27 18:11:15

我们有一些代码使用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应用程序的主线程上获得堆栈损坏,该应用程序使用工作线程来检查使用此计时器设置其值的类的属性。

。NET 4.0版本Windows 2008R2

编辑:

同样,当我们在WPF应用程序的主线程上得到堆栈损坏时,计时器事件处理程序调用的方法之一会抛出InvalidOperationException,并发送消息"Timeout expired"。从池中获取连接之前的超时时间。发生这种情况可能是因为所有池连接都在使用,并且达到了最大池大小。"

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;
            }
        }
    }
}

System.Timers.定时器,比interval更频繁地运行,使用多个线程

听起来好像数据库有连接池问题,计时器回调阻塞了对PingDatabase()的调用。这会导致多个计时器回调线程同时存在。你可以通过调用m_Timer来快速检查。在计时器函数的顶部启用= false,并调用m_Timer。在函数结束时Enabled = true。这应该导致在任何给定时间只有一个线程存在。

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