С# winform Два таймера обращаются к одной и той же переменной

Я новичок в С#, и я делаю проект, которому нужны два таймера для одновременного доступа к одной и той же переменной (один для чтения, а другой для записи или обновления). Итак, моя проблема заключается в том, какой таймер должен Я использую? Forms.Timer или Thread.Timer. Я читал какую-то статью об их различии. Поскольку я хочу использовать эти таймеры для обновления интерфейса программы (изображение в поле изображения), поэтому я думаю, что здесь следует использовать Forms.Timer, поскольку он связан с графическим интерфейсом. Однако порядок, в котором таймер выполняется первым, также имеет значение, поэтому я думаю, что Thread.Timer также следует учитывать. Можно ли как-то объединить их вместе?

Обновление: я делаю проект ЭКГ, поэтому в основном я продолжаю получать данные и хочу нарисовать их в форме. однако, поскольку рисование заняло около 40 мс, поэтому использование одного таймера будет иметь задержку, а мне нужно реальное время. (Например, если я установил интервал в 100 мс, то потребовалось 140 мс, чтобы закончить рисование одного кадра, который должен быть завершен в 100 мс. Это приведет к задержке 40 мс для каждого тика.) Поэтому мое решение использует один таймер для обновления буфера данных, когда я получаю данные, и использую другой таймер для вызова Invalidate, который перерисовывает все новые данные. Должен ли я использовать thread.timer для обновления данных и form.timer для перерисовки формы?


person oocharlesxx    schedule 14.12.2019    source источник
comment
Что вы имеете в виду, что порядок, в котором таймер выполняется первым, также имеет значение? Вы ожидаете, что два таймера сработают точно в одно и то же время и должны обрабатывать события в определенном порядке?   -  person John Wu    schedule 14.12.2019
comment
Вы должны придерживаться специального таймера WinForms. Таким образом вам не придется иметь дело с контролем доступа к вашим переменным через блокировки.   -  person Bradley Uffner    schedule 14.12.2019
comment
Что именно делает ваша программа? Похоже, что для этого может быть лучший образец.   -  person Rufus L    schedule 14.12.2019
comment
@Rufus L, привет, я только что отредактировал свой вопрос, не могли бы вы дать мне совет или лучшее решение?   -  person oocharlesxx    schedule 14.12.2019
comment
@JohnWu, я хочу, чтобы оба таймера выполнялись одновременно, один таймер рисовал данные, а другой обновлял их. Так что им не нужно ждать, пока друг друга закончат. Я знаю, что form.timer будет иметь поток распространения, отличный от основного потока, но что, если я использую два form.timer, они разрушаются в одном потоке?   -  person oocharlesxx    schedule 14.12.2019
comment
@oocharlesxx Я бы вообще не рекомендовал использовать таймеры. Существует Rx.NET, который позволяет вам сделать то, что вам нужно, в пару строк. Если вы работаете даже с эмиттером и вам нужно, чтобы процессор мог свободно использовать существующие фреймворки, вы получите от них много преимуществ во многих аспектах (ремонтопригодность/тестируемость/модифицируемость и т. д.). Сегодня вечером опубликую ответ с решением.   -  person fenixil    schedule 14.12.2019
comment
@oocharlesxx, не могли бы вы предоставить более подробную информацию о том, как вы получаете данные? это синхронизация или асинхронность, вытягивание или нажатие (вы вызываете метод и получаете результат или подписываетесь на какое-то событие)?   -  person fenixil    schedule 14.12.2019
comment
@fenixil, привет, я только что делал http-запрос каждые 5 секунд и сохранял данные в буфере (массив байтов).   -  person oocharlesxx    schedule 14.12.2019
comment
Добавьте событие в ваш приемник proc. Создавайте событие при получении новых данных, передавая их в пользовательском классе EventArgs. Подпишитесь на событие в своей форме, затем Invalidate() элемент управления, используемый в качестве холста для рисования новых данных.   -  person Jimi    schedule 14.12.2019
comment
Добавление к тому, что сказал @Jimi. Хитрость в обеспечении бесперебойной работы заключается в том, чтобы сделать рисунок в обработчике Paint, а затем тщательно управлять областями инвалидации. Обработайте входящие данные, когда они поступят, а затем аннулируйте только ту область, которая нуждается в обновлении. Некоторое время спустя будет вызвана ваша процедура Paint. Будет обновлен только недействительный регион   -  person Flydog57    schedule 15.12.2019


Ответы (1)


Основное различие между обоими таймерами заключается в том, что Form.Timer работает в том же потоке, что и ваш Form, поэтому нет проблем с доступом или изменением состояния любого компонента графического интерфейса (элемент управления и т. д.) с помощью кода обработчика событий Tick. В случае Thread.Timer нет гарантии, что метод TimerCallback будет вызван из текущего потока (может быть, но не обязательно), поэтому доступ к компонентам GUI может быть немного сложным и непростым (вы должны использовать Invoke(), как здесь: Доступ к элементу управления формы из отдельного потока). С другой стороны, любая длительная и интенсивная обработка, реализованная в обработчике Form.Timer.Tick, будет выполняться в том же потоке, что и GUI, что может снизить эффективность и ответственность GUI. Итак, общее правило таково: для быстрых, краткосрочных операций с компонентами GUI используйте Form.Timer, а для длительных, тяжелых вычислений, не требующих доступа к компонентам GUI, используйте Thread.Timer. Конечно, это упрощенное правило - окончательное решение должно зависеть от конкретного случая.

person VillageTech    schedule 14.12.2019
comment
Итак, я должен использовать thread.Timer для обновления буфера данных, так как ему нужно больше вычислений, и form.Timer для перерисовки формы, верно? Еще один вопрос: они работают в одном потоке? - person oocharlesxx; 14.12.2019
comment
Правильно. О запущенном потоке, как я уже писал: обработчик событий Form.Timer.Tick будет работать с потоком GUI, а Thread.Timer.TimerCallback в основном и обычно работает с потоком, отличным от GUI. - person VillageTech; 14.12.2019