如何使用 asio 执行非阻塞读取? [英] How do I perform a nonblocking read using asio?

查看:12
本文介绍了如何使用 asio 执行非阻塞读取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 boost::asio 从串行端口上的设备读取和写入.boost::asio:read() 和 boost::asio::serial_port::read_some() 都在没有东西可读时阻塞.相反,我想检测这种情况并向端口写入命令以启动设备.

I am attempting to use boost::asio to read and write from a device on a serial port. Both boost::asio:read() and boost::asio::serial_port::read_some() block when there is nothing to read. Instead I would like to detect this condition and write a command to the port to kick-start the device.

我怎样才能检测到没有可用数据?

How can I either detect that no data is available?

如果有必要,我可以异步完成所有事情,如果可以,我宁愿避免额外的复杂性.

If necessary I can do everything asynchronously, I would just rather avoid the extra complexity if I can.

推荐答案

实际上,您有几个选择.您可以使用串口内置的async_read_some函数,也可以使用独立函数boost::asio::async_read(或async_read_some).

You have a couple of options, actually. You can either use the serial port's built-in async_read_some function, or you can use the stand-alone function boost::asio::async_read (or async_read_some).

您仍然会遇到实际上被阻止"的情况,因为除非 (1) 已读取数据或 (2) 发生错误,否则这些都不会调用回调.为了解决这个问题,您需要使用 deadline_timer 对象来设置超时.如果超时首先触发,则没有可用数据.否则,您将读取数据.

You'll still run into the situation where you are effectively "blocked", since neither of these will call the callback unless (1) data has been read or (2) an error occurs. To get around this, you'll want to use a deadline_timer object to set a timeout. If the timeout fires first, no data was available. Otherwise, you will have read data.

增加的复杂性并不是那么糟糕.您最终会得到两个具有相似行为的回调.如果读取"或超时"回调因错误而触发,则您知道它是比赛失败者.如果其中任何一个没有错误地触发,那么您就知道它是比赛的获胜者(并且您应该取消另一个调用).在您将阻塞调用 read_some 的地方,您现在将调用 io_svc.run().您的函数在调用 run 时仍会像以前一样阻塞,但这次您可以控制持续时间.

The added complexity isn't really all that bad. You'll end up with two callbacks with similar behavior. If either the "read" or the "timeout" callback fires with an error, you know it's the race loser. If either one fires without an error, then you know it's the race winner (and you should cancel the other call). In the place where you would have had your blocking call to read_some, you will now have a call to io_svc.run(). Your function will still block as before when it calls run, but this time you control the duration.

这是一个例子:

void foo()
{
  io_service     io_svc;
  serial_port    ser_port(io_svc, "your string here");
  deadline_timer timeout(io_svc);
  unsigned char  my_buffer[1];
  bool           data_available = false;

  ser_port.async_read_some(boost::asio::buffer(my_buffer),
      boost::bind(&read_callback, boost::ref(data_available), boost::ref(timeout),
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred));
  timeout.expires_from_now(boost::posix_time::milliseconds(<<your_timeout_here>>));
  timeout.async_wait(boost::bind(&wait_callback, boost::ref(ser_port),
                  boost::asio::placeholders::error));

  io_svc.run();  // will block until async callbacks are finished

  if (!data_available)
  {
    kick_start_the_device();
  }
}

void read_callback(bool& data_available, deadline_timer& timeout, const boost::system::error_code& error, std::size_t bytes_transferred)
{
  if (error || !bytes_transferred)
  {
    // No data was read!
    data_available = false;
    return;
  }

  timeout.cancel();  // will cause wait_callback to fire with an error
  data_available = true;
}

void wait_callback(serial_port& ser_port, const boost::system::error_code& error)
{
  if (error)
  {
    // Data was read and this timeout was canceled
    return;
  }

  ser_port.cancel();  // will cause read_callback to fire with an error
}

这应该让您开始时只需进行一些调整即可满足您的特定需求.我希望这会有所帮助!

That should get you started with only a few tweaks here and there to suit your specific needs. I hope this helps!

另一个注意事项:不需要额外的线程来处理回调.一切都在对 run() 的调用中处理.不知道您是否已经意识到这一点...

Another note: No extra threads were necessary to handle callbacks. Everything is handled within the call to run(). Not sure if you were already aware of this...

这篇关于如何使用 asio 执行非阻塞读取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆