从计时器线程调用System.Timers.Timer.Stop

时间:2016-02-03 16:52:54

标签: c# multithreading timer

在下面的C#代码中,从计时器线程调用System.Timers.Timer.Stop,但也从UI线程调用:

private void StartTimer()
{
    // This is in the context of the UI thread.
    this.m_timer = new System.Timers.Timer(1000);

    this.m_timer.Elapsed += (sender, e) =>
    {
        // This is in the context of the timer thread.

        try
        {
            this.m_timer.Stop();

            // Do some stuff.

            this.m_timer.Start();
        }
        catch (Exception exception)
        {
            CTrace.Exception(this, "StartTimer", exception);
        }
    };
    this.m_timer.Start();
}
// After returning from the StartTimer() method, this.m_timer.Stop() 
// will be called from the UI thread.

从计时器线程安全调用System.Timers.Timer.StartSystem.Timers.Timer.Stop吗?它是线程安全的吗? 谢谢!

1 个答案:

答案 0 :(得分:1)

不,Stop()Start()方法在MSDN的文档中未列为线程安全。

为了最安全,您应该在使用多个线程时锁定MSDN中未列为线程安全的所有操作。

然而,您的代码还有其他问题,您在启动新计时器时会替换this.m_timer,但是在计时器回调代码中您也使用this.m_timer,这意味着如果您启动计时器然后启动第二个回调将使用相同的m_timer。您应该只使用一个计时器而不是在启动函数内创建它。

此外,您无需手动停止将计时器设置AutoReset设置为false,而是提供您尝试自动执行的操作。

private object m_timerLock;
private bool m_timerRunning = false;

public YourClass()
{
    this.m_timer = new System.Timers.Timer(1000);
    this.m_timer.AutoReset = false;
    this.m_timer.Elapsed += TimerCallback;
}

private void StartTimer()
{
    // This is in the context of the UI thread.
    lock(this.m_timerLock)
    {
        this.m_timerRunning = true;
        this.m_timer.Start();
    }
}

private void TimerCallback(object sender, EventArgs e)
{
    // This is in the context of the timer thread.

    try
    {
        //This line is not needed anymore because of the this.m_timer.AutoReset = false.
        //this.m_timer.Stop();

        // Do some stuff.

        lock(this.m_timerLock)
        {
            //This checks to see if StopTimer() was called while the callback was running.
            if(this.m_timerRunning)
                this.m_timer.Start();
        }
    }
    catch (Exception exception)
    {
        CTrace.Exception(this, "StartTimer", exception);
    }
}

public void StopTimer()
{
    lock(this.m_timerLock)
    {
        this.m_timer.Stop();
        this.m_timerRunning = false;
    }
}