#c_sharp #net #многопоточность
Есть поток, который в цикле ожидает данные от ком-порта (или любого другого интерфейса)
и при их поступлении вызывает событие OnFrameReceived(...). Мне нужно написать блокирующий
метод SendAndWaitReply(...), который отправит данные по ком-порту и будет ждать ответа
(события OnFrameReceived) или таймаута операции (если ответ не придет).
Подскажите, как организовать синхронизацию потока чтения и потока, отправляющего команду?
public class Device
{
Connection connection = new Connection(...);
public Device()
{
connection.FrameReceived += Connection_FrameReceived;
}
// Отправить пакет и дождаться ответа/таймаута
public void SendAndWaitReply(ITxFrame frame)
{
bool timeout = false;
// Отправить пакет и заблокировать поток до наступления таймаута или приема
ответа
if(timeout)
{
throw new TimeoutException();
}
}
// Событие приема пакета
private void Connection_FrameReceived(object sender, RxFrame frame)
{
// Разблокировать поток, ожидающий приема пакета
// Обработка принятого пакета
}
}
Ответы
Ответ 1
Не знаю, можно ли проще: public class Device { private object _sendAndWaitReplySyncObject = new object(); private AutoResetEvent _frameReceivedEvent = new AutoResetEvent(false); private AutoResetEvent _frameAcceptedEvent = new AutoResetEvent(false); private AutoResetEvent _timeoutEvent = new AutoResetEvent(false); private ManualResetEvent _outsideSendAndWaitReplyEvent = new ManualResetEvent(true); // Отправить пакет и дождаться ответа/таймаута public void SendAndWaitReply(object frame) { try { lock (_sendAndWaitReplySyncObject) { // переводим все эвенты в not signaled состояние _outsideSendAndWaitReplyEvent.Reset(); _frameReceivedEvent.Reset(); _frameAcceptedEvent.Reset(); _timeoutEvent.Reset(); // Отправить пакет bool timeout = !_frameReceivedEvent.WaitOne(3000); if (timeout) { _timeoutEvent.Set(); // для того, что бы блок finally не сработал раньше времени _frameReceivedEvent.WaitOne(); throw new TimeoutException(); } else { _frameAcceptedEvent.Set(); // для того, что бы блок finally не сработал раньше времени _frameReceivedEvent.WaitOne(); } } } finally { // что бы Connection_FrameReceived не ждал вечно на вызове WaitAll _outsideSendAndWaitReplyEvent.Set(); } } // Событие приема пакета private void Connection_FrameReceived(object sender, object frame) { _frameReceivedEvent.Set(); // Разблокировать поток, ожидающий приема пакета int index = WaitHandle.WaitAny(new WaitHandle[] { _outsideSendAndWaitReplyEvent, _frameAcceptedEvent, _timeoutEvent }); switch (index) { case 0: // событие сработало вне метода SendAndWaitReply break; case 1: _frameReceivedEvent.Set(); // Обработка принятого пакета break; case 2: _frameReceivedEvent.Set(); // сработал _timeoutEvent break; } } }
Комментариев нет:
Отправить комментарий