Frage

Ich versuche Schub zu verwenden :: asio zu lesen und von einem Gerät an einer seriellen Schnittstelle zu schreiben. Beide boost :: asio: read () und boost :: asio :: serial_port :: read_some () blockieren, wenn es nichts zu lesen. Ich würde stattdessen möchte diesen Zustand erkennen und einen Befehl an den Port schreiben, um das Gerät anzukurbeln.

Wie kann ich entweder feststellen, dass keine Daten verfügbar sind?

Bei Bedarf ich alles asynchron tun kann, würde ich nur eher vermeiden, dass die zusätzliche Komplexität, wenn ich kann.

War es hilfreich?

Lösung

Sie haben ein paar Optionen, eigentlich. Sie können entweder die serielle Schnittstelle des eingebauten in async_read_some Funktion verwenden, oder Sie können den Stand-alone-Funktion boost::asio::async_read (oder async_read_some).

Sie werden immer noch in die Situation kommen, wo man effektiv „blockiert“ ist, da es sei denn, den Rückruf weder von diesen nennen (1) Daten gelesen wurden oder (2) ein Fehler auftritt. Um dies zu umgehen, sollen Sie ein deadline_timer Objekt verwenden, um ein Timeout zu setzen. Wenn das Timeout erstes feuert, waren keine Daten verfügbar. Andernfalls werden Sie lesen Daten haben.

Die zusätzliche Komplexität ist nicht wirklich so schlecht. Sie werden sich mit zwei Rückrufe mit ähnlichem Verhalten beenden. Wenn entweder die „Lesen“ oder der „timeout“ Callback-Brand mit einem Fehler, Sie wissen, dass es das Rennen Verlierer. Wenn entweder ein Feuer ohne einen Fehler, dann wissen Sie es das Rennen des Siegers (und Sie sollten den anderen Anruf abzubrechen). An der Stelle, wo Sie Ihren blockierenden Anruf hätten read_some, werden Sie nun einen Anruf müssen io_svc.run(). Ihre Funktion wird immer noch blockiert nach wie vor, wenn es ruft run, aber dieses Mal sind Sie steuern die Dauer.

Hier ist ein Beispiel:

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
}

Das sollten Sie mit nur ein paar Veränderungen hier und da passen Ihre spezifischen Bedürfnisse gestartet. Ich hoffe, das hilft!

Noch ein Hinweis: Keine zusätzlichen Fäden waren notwendig, Rückrufe zu handhaben. Alles ist innerhalb des Call behandelt run(). Nicht sicher, ob Sie waren bereits bekannt, diese ...

Andere Tipps

Es ist eigentlich viel einfacher als die Antworten hier haben angedeutet, und Sie können es tun synchron:

Angenommen, Ihre Sperrung Lese so etwas wie dies:

size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);

Dann ersetzen Sie es mit

socket.non_blocking(true);
size_t len = 0;
error = boost::asio::error::would_block;
while (error == boost::asio::error::would_block)
    //do other things here like go and make coffee
    len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint, 0, error);
std::cout.write(recv_buf.data(), len);

Sie verwenden die Alternative überlastet Form receive_from die fast alle die Sende- / Empfangsverfahren haben. Sie nehmen leider ein Argument flags aber 0 scheint gut zu funktionieren.

Sie haben die freie Funktion Asio verwenden :: async_read.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top