There is a device that periodically sends packets to the com port. You can also send a command to the device, to which it must respond with a confirmation.
I want to implement a blocking command transfer method that will return control when an answer is received, or throw an exception if the waiting time expires.
Since the device itself periodically sends messages that need to be sent, data is received in a separate stream, and after receiving the entire packet, a packet reception event is generated. The structure is as follows:
Frame lastTxFrame; // последняя отправленная команда // Отправить пакет и дождаться ответа или таймаута void Send(Frame frame) { lastTxFrame = frame; serialPort.Write(frame); /* заблокировать поток, дождаться ответа или таймаута */ } // Принято сообщение void OnFrameReceived(object sender, Frame rxFrame) { if(lastTxFrame != null && IsReply(lastTxFrame, rxFrame)) { /* разблокировать поток, ожидающий ответ */ } } // Проверить является ли сообщение reply ответом на команду command bool IsReply(Frame command, Frame reply) { return true; } How can you implement this algorithm so that there is no race race? You can start a timer after sending a packet, and detect a timeout in the callback method, and if a packet arrives, stop the timer. But in the description of System.Threading.Timer it is said that after calling Dispose a callback call may occur. So theoretically, we can both get an answer and catch a timeout.
You can use Interlocked methods to determine whether the callback timer or the message receiving handler was called:
int timeout = 0; void OnFrameReceived(object sender, Frame rxFrame) { if(Interlocked.CompareExchange(ref timeout, 1, 0) == 0) // таймаута не было { } } void TimerCallback(object state) { if (Interlocked.CompareExchange(ref timeout, 2, 0) == 0) // таймаут { } } But in this case, it is not clear how to reset the timeout variable to its original value in order to send the next message.
How to correctly implement the wait?
Sendis single-threaded, this can be easily implemented via a ManualResetEvent or ManualResetEventSlim . - VasekSend? - Vasek