2014-09-16 3 views
1

Пожалуйста, будьте добры, я просто изучаю C# и наследую это приложение от бывшего сотрудника - это мой первый проект C#.Непоследовательные интервалы с System.Windows.Forms.Timer

Я наблюдаю непоследовательные и медленные периоды с помощью System.Windows.Forms.Timer. Приложение написано на C# с MS Visual Studio.

Таймер установлен на интервал 100 мс, но я наблюдаю периоды от 110 мс до 180 мс.

Я использую несколько инструментов для наблюдения этого в то числе: - на SW осциллографа (пакета Iocomp.Instrumentation.Plotting.Plot), - настоящий осциллограф, - Позволить запуск таймера в течение некоторого времени и сравнивая число тиков * 100 мс как для системного времени, так и для секундомера.

Во всех случаях я наблюдаю 10% -ное отставание, которое становится очевидным в течение первых нескольких секунд.

Методы, выполняемые с каждым тиком, занимают менее 4 мс для запуска. Также не происходит асинхронной обработки времени. Однако это не имеет значения, поскольку таймер-таймер является прерыванием, а не событием, добавленным в очередь обработчика событий (насколько я знаю).

У кого-нибудь возникла такая проблема? Каковы были причины?

Спасибо.

+1

выглядит так уже решен Андре Saffin (http://stackoverflow.com/questions/21027375/how-to- [для ссылки нажмите здесь] c-sharp-несколько-точные таймеры-точно-для-10-миллисекунд-интервал) – 2014-09-16 18:58:28

+0

Спасибо за ответ. Я ценю это. – ErikB

ответ

1

Да, я всегда сталкивался с этой проблемой с System.Windows.Forms.Timer, так как он не фиксирует точно (большую часть времени). Вы можете попробовать System.Timers.Timer вместо этого и это вызывает прерывание точно (по крайней мере для 100мс точности)

0

System.Windows.Forms.Timer действительно просто оберткой для родного WM_TIMER сообщения. это означает, что сообщение таймера помещается в очередь сообщений в момент, близкий к запрошенному вами интервалу (плюс или минус ... здесь нет никакой гарантии). , когда обрабатывается это сообщение, полностью зависит от других сообщений в очереди и от того, сколько времени требуется на обработку. Например, если вы блокируете поток пользовательского интерфейса (и тем самым блокируете очередь от обработки новых сообщений), вы не получите событие таймера до момента разблокирования.

Windows - это не операционная система в режиме реального времени, вы не можете рассчитывать на точную точность таймеров. Если вам нужно что-то более мелкозернистое, лучшим выбором будет мультимедийный таймер.

+0

Спасибо за ответ, Питер. Я знал, что Windows - это не ОСРВ, я просто не понимал, насколько это нереально. Я работал только с встроенными устройствами с RTOS или механизмом прерывания/очереди, который я написал сам. Доверяя Windows - это совершенно новая вещь для меня. – ErikB

5

Таймеры такие же точные, как и прерывание тактовой синхронизации операционной системы. Какая отметка 64 раза в секунду по умолчанию, 15.625 мс. Вы не можете получить чистый интервал 100 мс от этого, он не делится на 15.625. Вы получаете следующее целое число, 7 x 15.625 = 109.375 msec. Очень близко к 110 мсек вы наблюдали.

Необходимо добавить задержку при обращении с уведомлением о тайме на этот теоретический минимум. Таймеры должны конкурировать со всем остальным, что происходит в вашем потоке пользовательского интерфейса. Они обрабатываются как наименьшее важное уведомление, которое должно быть доставлено. Сначала отправляются отправленные сообщения, затем вводится пользовательский ввод, затем следующая картина, последние сообщения таймера. В любом случае, если у вас есть сложный пользовательский интерфейс, который требует времени для перерисовки, то событие Tick будет задержано до тех пор, пока это не будет выполнено. То же самое для любого обработчика событий, который вы пишете, который делает что-то нетривиальное, например, чтение файла или запрос dbase.

Чтобы получить более гибкий таймер, который не страдает от такого задержек, вам необходимо использовать асинхронный таймер. System.Threading.Timer или System.Timers.Timer. Избегайте последнего. Их обратный вызов работает в потоке threadpool, поэтому может работать довольно быстро. Будьте очень осторожны, что вы делаете в этом обратном вызове, много вещей, которые вы не можете сделать, потому что они не являются потокобезопасными.

Эти таймеры могут быть более точными, изменяя тактовую частоту прерывания. Для этого требуется pinvoke, call timeBeginPeriod(). timeEndPeriod(), когда вы закончите.

+0

Ничего себе, замечательный ответ, Ганс. Большое спасибо за объяснение. – ErikB

0

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

От https://msdn.microsoft.com/en-us/library/system.windows.forms.timer(v=vs.110).aspx (курсив мой):

Windows Forms компонент Таймер однопоточный, и до с точностью до 55 миллисекунд. Если вам требуется многопоточный таймер с большей точностью, используйте класс Timer в пространстве имен System.Timers.

Так с Windows.Forms.Timer вы можете получить 55ms, 110ms, 165ms и т. Д .; что согласуется с тем, что вы видели. Если вам нужна более высокая точность, попробуйте System.Timers.Timer или System.Threading.Timer

Смежные вопросы