У меня есть приложение, которое взаимодействует с микроконтроллером через последовательный порт. Я хочу периодически проверять статус контроллера в фоновом режиме, а также позволять пользователю взаимодействовать с контроллером асинхронно (через пользовательский интерфейс), отправляя команды и получая ответы.Как синхронизировать операции SerialPort?
Пользовательский интерфейс и фон Работник использовать SerialCommunication статический класс:
static class SerialCommunication
{
static SerialPort serialPort;
static int readWriteTimeout = 1000; // [ms]
static int waitForTransmissionTimeout = 2; // [s]
static string rxData = "", endOfString = "" + char.MinValue;
static bool WaitingForSerialData = false; // Set in SerialWrite(), cleared in SerialRead()
[...]
public static string SerialRead()
{
try
{
rxData = serialPort.ReadTo(endOfString);
}
catch (TimeoutException)
{
WaitingForSerialData = false;
throw new Exception(Properties.Resources.serial_read_timeout);
}
WaitingForSerialData = false;
return rxData;
}
public static void SerialWrite(string text)
{
DateTime start = DateTime.Now;
while (WaitingForSerialData) // Avoids the situation in which a command executed on a thread receives the response for the command executed from a different thread
{
if (!WaitingForSerialData)
{
try
{
WaitingForSerialData = true; // All commands wait for confirmation/data, so it is normal to set this boolean value for every serial transmission
serialPort.Write(text);
}
catch (TimeoutException)
{
throw new Exception(Properties.Resources.serial_write_timeout);
}
}
else
{
System.Threading.Thread.Sleep(100);
if ((DateTime.Now - start).Seconds >= waitForTransmissionTimeout)
{
throw new Exception("Timeout");
}
}
}
}
}
Последовательный порт инициализируется при запуске приложения. SerialWrite
и SerialRead
вызываются в пользовательском интерфейсе или в фоновом режиме последовательно.
Я хочу избежать ситуаций, когда команда получает ответ от другой команды, выполненной в другом потоке. В настоящее время я выполнил ожидание в SerialWrite для получения команды (для завершения SerialRead) перед отправкой команды, но я боюсь, что это может заблокировать пользовательский интерфейс (до waitForTransmissionTimeout
секунд), если SerialWrite выполняется из там.
Каков наилучший способ синхронизации операций SerialPort?
Итак, _все_ команды SerialWrite с последующим SerialRead для получения ответа? Если да, почему бы вам не объединить операции чтения и записи в одиночном SendCommand или что-то еще? – Evk
@Evk Но что будет, если SendCommand выполняется, например, в потоке Background Worker и сразу после (до его завершения) в пользовательском интерфейсе? –
Вы должны защищать всю операцию (писать + с последующим считыванием) с помощью простой блокировки. Затем, если UI отправляет команду перед завершением работы фонового работника - он будет ждать, пока это не будет выполнено. Конечно, вы не должны выполнять эту операцию из потока пользовательского интерфейса в любом случае. Выполните его из фонового потока, а затем верните результат обратно в поток пользовательского интерфейса, когда закончите (чтобы показать пользователю результат). Никогда не выполняйте такие действия непосредственно в потоке пользовательского интерфейса. – Evk