C# 调用DeleteTimerQueueTimer时发生SEHExException

C# 调用DeleteTimerQueueTimer时发生SEHExException,c#,timer,C#,Timer,我使用的计时器类包装了CreateTimerQueueTimer和DeleteTimerQueueTimer 下面是课堂: using System; using System.Threading; using MyCompany.Internal; using TimerCallback = MyCompany.Internal.TimerCallback; public class Timer : IDisposable { public Timer() {

我使用的计时器类包装了
CreateTimerQueueTimer
DeleteTimerQueueTimer

下面是课堂:

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;
}
使用系统;
使用系统线程;
使用MyCompany.Internal;
使用TimerCallback=MyCompany.Internal.TimerCallback;
公共类计时器:IDisposable
{
公共计时器()
{
this.callback=this.ticked;
this.autoReset=true;
计算机。将时间解决方案更改为(1);
this.priority=ThreadPriority.Normal;
}
公共虚拟事件EventHandler已过期;
公共虚拟布尔自动重置
{
得到
{
返回此.autoReset;
}
设置
{
this.autoReset=值;
}
}
公共虚拟线程优先级
{
得到
{
返回此项。优先级;
}
设置
{
这个。优先级=值;
}
}
公共虚拟无效开始(整数间隔)
{
如果(间隔<1)
{
抛出新ArgumentOutOfRangeException(“interval”,“interval必须至少为1毫秒”);
}
if(联锁比较交换(参考this.started,1,0)==1)
{
返回;
}
NativeMethods.CreateTimerQueueTimer(
把这个拿出来,
IntPtr.Zero,
这个.回调,,
IntPtr.Zero,
(uint)间隔,
(uint)间隔,
CallbackOptions.ExecuteInTimerThread);
}
公共虚拟无效停止()
{
if(联锁比较交换(参考this.started,0,1)==0)
{
返回;
}
NativeMethods.DeleteTimerQueueTimer(IntPtr.Zero、this.handle、IntPtr.Zero);
}
公共虚拟void Dispose()
{
这个。停止();
}
勾选私有无效(IntPtr参数指针,布尔未使用)
{
如果(!this.AutoReset)
{
这个。停止();
}
Thread.CurrentThread.Priority=此.Priority;
var-appeased=这个.appeased;
如果(已过!=null)
{
已过(此为EventArgs.Empty);
}
}
私有int启动;
私有IntPtr句柄;
私有易失性bool-autoReset;
私有线程优先级;
私有只读TimerCallback回调;
}
问题是,过了一段时间,当从多个线程同时调用Start和Stop时,我得到了一个SEHException。调用
Stop()
后,
互锁.compareeexchange
方法应防止DeleteTimerQueueTimer被调用一次,对吗?即使从不同线程同时调用
Stop()


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

该函数是互锁的。CompareExchange防止了变量“started”被两个线程同时修改,但计时器的句柄才是您想要保护的真正的,但在某些情况下,代码无法做到这一点

例如,线程A调用start函数,它执行Interlocked.CompareExchange函数,然后this.started为1;此时线程A调用stop函数,它看到'started'是一个,因此它将调用函数DeleteTimerQueueTimer来删除计时器,而计时器可能尚未创建,句柄无效


因此,您应该保护计时器的句柄

您创建了多少个计时器实例?每个线程都有自己的时间实例吗?一个计时器实例用于所有线程。每个线程都会引发一个事件,
Stop()
s在其处理方法开始时启动计时器,并在其处理方法结束时重新启动计时器。基本上,我想在线程引发事件或计时器过期时刷新屏幕上的内容(以防有一段时间没有线程引发事件)。