调用DeleteTimerQueueTimer时出现SEHException

时间:2014-04-10 18:43:57

标签: c# timer

我正在使用包裹CreateTimerQueueTimerDeleteTimerQueueTimer的Timer类。

这是班级:

using System;
using System.Threading;
using MyCompany.Internal;
using TimerCallback = MyCompany.Internal.TimerCallback;

public class Timer : IDisposable
{
    public Timer()
    {
        this.callback = this.ticked;
        this.autoReset = true;
        Computer.ChangeTimerResolutionTo(1);
        this.priority = ThreadPriority.Normal;
    }

    public virtual event EventHandler Elapsed;

    public virtual bool AutoReset
    {
        get
        {
            return this.autoReset;
        }

        set
        {
            this.autoReset = value;
        }
    }

    public virtual ThreadPriority Priority
    {
        get
        {
            return this.priority;
        }

        set
        {
            this.priority = value;
        }
    }

    public virtual void Start(int interval)
    {
        if (interval < 1)
        {
            throw new ArgumentOutOfRangeException("interval", "Interval must be at least 1 millisecond.");
        }

        if (Interlocked.CompareExchange(ref this.started, 1, 0) == 1)
        {
            return;
        }

        NativeMethods.CreateTimerQueueTimer(
            out this.handle,
            IntPtr.Zero,
            this.callback,
            IntPtr.Zero,
            (uint)interval,
            (uint)interval,
            CallbackOptions.ExecuteInTimerThread);
    }

    public virtual void Stop()
    {
        if (Interlocked.CompareExchange(ref this.started, 0, 1) == 0)
        {
            return;
        }

        NativeMethods.DeleteTimerQueueTimer(IntPtr.Zero, this.handle, IntPtr.Zero);
    }

    public virtual void Dispose()
    {
        this.Stop();
    }

    private void ticked(IntPtr parameterPointer, bool unused)
    {
        if (!this.AutoReset)
        {
            this.Stop();
        }

        Thread.CurrentThread.Priority = this.Priority;
        var elapsed = this.Elapsed;
        if (elapsed != null)
        {
            elapsed(this, EventArgs.Empty);
        }
    }

    private int started;
    private IntPtr handle;
    private volatile bool autoReset;
    private ThreadPriority priority;
    private readonly TimerCallback callback;
}

问题是,在一段时间后,当我从多个线程同时调用Start和Stop时,我遇到了SEHException。 Interlocked.CompareExchange方法应该阻止在调用Stop()后调用DeleteTimerQueueTimer,对吧?即使从不同的线程同时调用Stop()

SEHExceptionDeleteTimerQueueTimer()抛出;我认为这是因为它试图删除已经删除的计时器,使得句柄无效。 CompareExchange是否阻止DeleteTimerQueueTimer被多次调用,即使多个线程同时被调用?

1 个答案:

答案 0 :(得分:1)

Interlocked.CompareExchange函数阻止变量&#39; start&#39;从2个线程同时修改,但定时器的句柄是你想要保护的真实的,但代码在某些情况下无法做到。

例如,线程A调用start函数,它执行函数Interlocked.CompareExchange然后this.started为1;此时线程A调用停止功能,它看到&#39;已启动&#39;是一个,所以它将调用函数DeleteTimerQueueTimer来删除定时器,而定时器可能尚未创建,并且句柄无效。

所以你应该保护计时器的句柄