Есть ли замена .NET для методов timeBeginPeriod и timeEndPeriod?

Я работал над программой, которая обменивается данными через SerialPort, и у меня возникла проблема с ней. Его коммуникация ниже 50% или меньше. Если нет, то в большинстве случаев время ожидания истекает.

Изучив эту проблему, я выяснил, что разрешение глобального или системного таймера по умолчанию составляет минимум 10 мс или больше.

Последовательная связь (RTS) и Windows 7

Итак, если вы используете Thread.Sleep в своем общении для паузы на X миллисекунд, лучшее, что он может сделать, - это 10 мс или больше для бездействия или паузы.

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

Единственный способ решить эту проблему - настроить или изменить разрешение системного таймера. Для этого мне сказали использовать методы Windows timeBeginPeriod и timeEndPeriod из winmm.dll. Хотя я могу импортировать эти методы в свою версию моей программы для Windows .NET, я хотел бы знать, есть ли какая-либо замена для этих методов в платформах .NET.


person ThN    schedule 05.11.2012    source источник
comment
Скорость отклика события DataReceived SerialPort не имеет ничего общего с разрешением таймера. Он использует ожидаемое событие, которое вызывает переключение контекста потока, когда драйвер сообщает о событии приема данных. Ожидание гарантированных откликов в 10 мс - безнадежное дело в Windows, это не операционная система реального времени. Требуется драйвер.   -  person Hans Passant    schedule 05.11.2012
comment
@HansPassant, нет. Дело не в DataReceived. Я тоже пробовал это, и это само по себе доставило мне больше горя, чем решило мою проблему. Итак, я создал единый поток для записи и чтения через последовательный порт. Точно зная, сколько времени требуется, чтобы устройство ответило, я на мгновение приостанавливаю свое программное обеспечение, чтобы переключить ЛИНИЮ (RTS) для чтения. После чтения переключает линию (rts) на запись. Это займет всего 2 или 3 миллисекунды. Итак, я использую thread.sleep. Как описано выше, thread.sleep (1) будет ждать 10 мс или более. Ганс, это может быть потеряно, но мое общение было твердым на 100% после 3 недель головной боли.   -  person ThN    schedule 05.11.2012
comment
В этом мало смысла. Зачем вообще спать? Просто вызовите Read () напрямую без any сна, он вернется только тогда, когда что-то получено.   -  person Hans Passant    schedule 05.11.2012
comment
@HansPassant, Драйвер нужен ??? Чего в Visual Studio 2010 недостаточно? Ничего особенного не устанавливал. Я использую инструмент фреймворка SerialPort, поставляемый с Visual Studio 2010. После нескольких настроек я могу общаться. Вероятно, используется общий драйвер.   -  person ThN    schedule 05.11.2012
comment
Мне кажется, вы делаете довольно классическую ошибку при чтении данных из последовательного порта. Вы игнорируете возвращаемое значение вызова SerialPort.Read (). Это будет не количество байтов, которое вы запрашиваете. Да, вызов Sleep () - это повязка для этого, он задерживает вашу программу на достаточно долгое время, чтобы драйвер мог получить достаточно байтов. Однако это неправильный обходной путь, вместо этого вы должны продолжать вызывать Read (), пока не получите полный ответ устройства.   -  person Hans Passant    schedule 05.11.2012
comment
DataReceived не является надежным из того, что я испытал. Он не фиксирует все сразу. Фактически, в основном вы получаете биты и фрагменты байтов или данных, которые вы должны поместить в буфер для обработки. Это создало для меня больше проблем, чем решило какие-либо. Он не ждет, пока все байты поступят в его входной буфер, даже если вы установили для параметра ReceivedBytesThreshold желаемое значение.   -  person ThN    schedule 05.11.2012
comment
Захватить сразу все - ваша ошибка. Как я уже объяснил, сон не является решением этой проблемы, особенно в случае протокола, чувствительного ко времени. Просто продолжайте вызывать Read () в цикле. Будь то в обработчике событий DataReceived или сразу после включения RTS.   -  person Hans Passant    schedule 05.11.2012
comment
@HansPassant, я не думаю, что событие DataReceived имеет проблемы со сбором данных сразу. Прямо сейчас я читаю все данные сразу прямо из входного буфера последовательного порта без каких-либо проблем, но поскольку он срабатывает слишком рано, прежде чем все данные, отправленные с устройства, будут получены, он становится случайным. Для меня это большая проблема. Я могу заставить свою программу ждать прибытия всех данных немногим более 8 миллисекунд, и это не займет много времени. Из 500 000 хороших пакетов моя программа случайным образом обнаруживает около 56 таймаутов. Теперь это лучше, чем 80% таймаутов и 20% хороших пакетов. Тестировал весь день :)   -  person ThN    schedule 06.11.2012


Ответы (1)


Если ваша цель - избежать вызова специфичных для платформы функций DLL и просто использовать инфраструктуру .Net, тогда для коротких тайм-аутов лучше всего подойдет цикл с System.Diagnostics.Stopwatch.

Секундомер автоматически использует таймер высокого разрешения, если он есть.

public static void Pause(long ms) 
{
    Stopwatch t = new Stopwatch();
    t.Start();
    while(t.ElapsedMilliseconds < ms) { }
    t.Stop();
}

Это заблокирует ваш вызывающий поток и загрузит ЦП в цикле паузы, чтобы смягчить некоторые из них (если вы используете многоядерную систему, вы можете установить привязку вашего процесса или потока к другому ядру. Как установить привязку процессора в .NET?

person Louis Ricci    schedule 05.11.2012
comment
Вы также можете подумать о добавлении Thread.SpinWait(n) в цикл - person Basic; 19.10.2013