كيف يمكنني إجراء توصيل nonblocking قراءة باستخدام اسيو؟

StackOverflow https://stackoverflow.com/questions/456042

  •  19-08-2019
  •  | 
  •  

سؤال

وأنا محاولة لاستخدام دفعة :: اسيو القراءة والكتابة من جهاز على منفذ تسلسلي. كلا دفعة :: اسيو: قراءة () وتعزيز :: كتلة اسيو :: :: serial_port read_some () عندما يكون هناك شيء للقراءة. بدلا من ذلك أود أن الكشف عن هذا الشرط وإرسال الأوامر إلى ميناء لبدء تشغيل الجهاز.

وكيف يمكنني إما أن كشف أية بيانات متاح؟

إذا لزم الأمر أستطيع أن أفعل كل شيء بشكل غير متزامن، أود فقط بدلا تجنب تعقيد إضافي إذا ما أستطيع.

هل كانت مفيدة؟

المحلول

لديك عدة خيارات، في الواقع. يمكنك إما استخدام المدمج في وظيفة async_read_some المنفذ التسلسلي، وأو يمكنك استخدام وظيفة boost::asio::async_read مستقل (أو async_read_some).

وأنت لا تزال تعمل في الوضع حيث كنت على نحو فعال "المحظورة"، لأن أيا من هذه سيدعو الاستدعاء إلا إذا (1) تمت قراءة البيانات أو (2) يحدث خطأ. للالتفاف على هذا، فأنت تريد أن استخدام كائن deadline_timer لتحديد مهلة. إذا كانت مهلة حرائق أولا، لم يكن البيانات المتاحة. خلاف ذلك، سيكون لديك قراءة البيانات.

والتعقيد وأضاف ليست في الحقيقة كلها سيئة. سوف ينتهي بك الأمر مع اثنين من الاسترجاعات مع سلوك مماثل. إذا إما "قراءة" أو "مهلة" حرائق رد مع خطأ، وانت تعرف انها الخاسر السباق. إذا كان أي واحد الحرائق دون خطأ، فهذا يعني انك تعرف انها الفائز سباق (ويجب إلغاء المكالمة الأخرى). في المكان الذي من شأنه أن كان لديك استدعاء حظر لread_some، سيكون لديك الآن دعوة لio_svc.run(). وظيفة الخاص بك لا يزال يمنع كما كان من قبل عندما يدعو run، لكن هذه المرة كنت السيطرة على المدة.

وهنا مثال:

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
}

وهذا يجب ان تحصل على انك بدأته مع فقط بضعة تعديلات هنا وهناك لتناسب الاحتياجات المحددة الخاصة بك. آمل أن يساعد هذا!

وملاحظة أخرى: لا مواضيع اضافية ضرورية للتعامل مع رد. يتم التعامل مع كل ما في الدعوة إلى run(). لست متأكدا إذا كنت بالفعل على علم بذلك ...

نصائح أخرى

ولها في الواقع الكثير أبسط من الإجابات هنا قد ضمنا، ويمكنك أن تفعل ذلك بشكل متزامن:

لنفترض ان لديك حجب قراءة شيء من هذا القبيل:

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

وبعد ذلك تقوم باستبداله

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);

ويمكنك استخدام النموذج البديل طاقتها من receive_from التي لديها ما يقرب من جميع الإرسال / التلقي الأساليب. أنها للأسف تأخذ حجة الأعلام ولكن 0 يبدو للعمل بشكل جيد.

لديك لاستخدام وظيفة خالية اسيو :: async_read.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top