У меня есть std::thread
, который использует asio Boost для чтения из последовательного порта:
std::atomic<bool> quit(false);
void serialThread()
{
try
{
asio::io_service io;
asio::serial_port port(io);
port.open("COM9"); // Yeay no port enumeration support!
port.set_option(asio::serial_port_base::baud_rate(9600));
while (!quit)
{
asio::streambuf buf;
asio::read_until(port, buf, "\n");
auto it = asio::buffers_begin(buf.data());
string line(it, it + buf.size());
doStuffWithLine(line);
}
}
catch (std::exception e)
{
cout << "Serial thread error: " << e.what() << endl;
}
}
void SetupSignals()
{
// Arrange it so that `quit = true;` happens when Ctrl-C is pressed.
}
int main(int argc, char *argv[])
{
SetupSignals();
thread st(serialThread);
st.join();
return 0;
}
Когда я нажимаю Ctrl-C, я хочу чисто выйти из потока, чтобы все деструкторы вызывались соответствующим образом (некоторые драйверы в Windows ненавидят, если вы не закрываете их ресурсы правильно).
К сожалению, как видите, текущий код блокируется в read_until()
, поэтому при нажатии Ctrl-C ничего не произойдет, пока не будет получена новая строка текста.
Одним из решений является использование опроса, что-то вроде этого:
asio::async_read_until(port, buf, "\n", ...);
while (!quit)
io.poll();
Но я бы предпочел не использовать опрос. Это довольно неэлегантно. Единственное решение, которое я вижу в настоящее время, - это иметь std::condition_variable quitOrIoFinished
, который запускается либо когда quit
установлено в true, либо когда чтение заканчивается. Но я не писал asio, поэтому я не могу дать ему условную переменную для ожидания.
Есть ли какое-нибудь чистое здравое решение? В Go я бы просто использовал select
для ожидания на нескольких каналах, где один из них является каналом выхода. Однако я не вижу аналогичного решения на C++.
asio::read_until
. Установите этот тайм-аут, возможно, на 200 мс и проверьте, следует ли вам выйти, прежде чем пытаться снова. - person nwp   schedule 08.02.2016