Настраиваемый таймер код обзора для потокобезопасности


Я создал пользовательский таймер, чтобы удовлетворить следующим требованиям:

  • Точностью до миллисекунды
  • Я хочу, чтобы обработчик событий Tick быть только вызывается один раз для текущего обработчика тиков завершил (очень похоже на таймер приложения WinForms)
  • Я хочу, чтобы исключения в главном потоке пользовательского интерфейса, чтобы не быть поглощенными таймер-нить для этого необходимо вызвать/отправить вместо метода BeginInvoke/пост

Примечание: Я называю timeBeginPeriod(1)/ timeEndPeriod(1) для того, чтобы достичь точности до миллисекунд.

Я проверить, если таймер удаляется, чтобы убедиться, что удаление будет завершено, прежде чем таймер может быть создана вновь. Это выглядит ОК?

Для этого выполняется собственность, это возможно, что гоночные условия могло произойти?

...или это код к катастрофе и я должен попробовать (еще раз), чтобы получить CreateTimerQueueTimer на работу?

Код был протестирован с небольшим интервалом в 1 миллисекунду и большой интервал 300 мс с частыми пусками/остановками, и я до сих пор без проблем.

ЕТА: я нашел проблему с ним. Если таймер работает с интервалом в 1 миллисекунду, и я звоню, говорю, менять(300), он блокирует @ а (это.DeleteRequest). Это должно быть потому, что TimerLoop в этом.CallbackDelegate.Вызов(нуль) звонок.

public class MyTimer : IDisposable
{

    private System.Threading.TimerCallback CallbackDelegate;
    private bool DeleteRequest;

    private System.Threading.Thread MainThread;
    public MyTimer(System.Threading.TimerCallback callBack)
    {
        this.CallbackDelegate = callBack;
    }


    public void Create(int interval)
    {
        while (this.DeleteRequest) {
            System.Threading.Thread.Sleep(0);
        }

        if (this.MainThread != null) {
            throw new Exception("");
        }

        this.MainThread = new System.Threading.Thread(TimerLoop);
        // Make sure the thread is automatically killed when the app is closed.
        this.MainThread.IsBackground = true;
        this.MainThread.Start(interval);

    }

    public void Change(int interval)
    {
        // A lock required here?
        if (!this.IsRunning()) {
            throw new Exception("");
        }
        this.Delete();
        this.Create(interval);
    }

    public void Delete()
    {
        this.DeleteRequest = true;
    }

    public bool IsRunning()
    {
        return (this.MainThread != null) && this.MainThread.IsAlive;
    }


    private void TimerLoop(object args)
    {
        int interval = (int)args;
        Stopwatch sw = new Stopwatch();
        sw.Start();


        do {
            if (this.DeleteRequest) {
                this.MainThread = null;
                this.DeleteRequest = false;
                return;
            }

            long t1 = sw.ElapsedMilliseconds;

            // I want to wait until the operation completes, so I use Invoke.
            this.CallbackDelegate.Invoke(null);

            if (this.DeleteRequest) {
                this.MainThread = null;
                this.DeleteRequest = false;
                return;
            }

            long t2 = sw.ElapsedMilliseconds;

            int temp = Convert.ToInt32(Math.Max(interval - (t2 - t1), 0));
            sw.Reset();
            if (temp > 0) {
                System.Threading.Thread.Sleep(temp);
            }

            sw.Start();
        } while (true);

    }

        // dispose calls this.Delete();

}


1657
1
задан 8 сентября 2011 в 06:09 Источник Поделиться
Комментарии
1 ответ

Системы.Резьбонарезной.Нить.Сон() имеет точность (разрешение) около 15 миллисекунд, и поэтому я бы держаться подальше от использования, что в ваш код, если вам нужна точность до миллисекунд. Вы можете использовать секундомер , а? - при этом используется таймер высокого разрешения, где доступен, по умолчанию. Вы можете найти этот пост на StackOverflow здесь полезно, как хорошо.

1
ответ дан 12 сентября 2011 в 05:09 Источник Поделиться