Jochen Arndt
Как правило, все асинхронные операции ввода-вывода должны выполняться в собственных потоках, чтобы избежать блокировки приложения. В противном случае у вас будут лаги в графическом интерфейсе или графический интерфейс будет полностью заблокирован в худшем случае.
В вашем случае вам понадобится по крайней мере один поток для получения ответов и передачи команд в очереди.
Принимающий поток должен буферизировать данные до тех пор, пока не будет получен полный ответ. Как это сделать, зависит от данных (например, перевод строки с текстовыми данными или после получения количества байтов, объявленного в заголовке протокола).
Как только полный ответ получен, это сигнализируется другим потокам. В вашем случае это будет основной поток (GUI), чтобы показать ответ и очередь передачи, чтобы включить отправку следующей команды. Обратите внимание, что передача данных из потока в элементы графического интерфейса требует специальной обработки.
Поток передачи может просто отправить, используя блокирующий вызов, потому что он все равно должен ждать. После отправки он должен дождаться ответа полученного сигнала.
Вы можете поместить отправку и получение в один или два потока.
Псевдокод для приема (предполагая текстовые данные):
// Check for kill (terminate thread) event (wait with no timeout)
while (!KillEvent)
{
do
{
// Blocking call until a character is available
// Should have a timeout and corresponding handling (break here)
rxChar = ReceiveChar();
Buffer += rxChar;
}
while (rxChar != '\n');
// Signal other threads that a response has been received
// Pass a copy of Buffer to the main thread for display
}
В потоке передачи после отправки команды вызовите вышеописанное или дождитесь события, когда прием будет выполнен в собственном потоке.
Используя потоки и события, вы избегаете вызова
sleep
чего, как правило, следует избегать и гарантировать, что системное время не будет потрачено впустую.