كيف يمكنني إجراء توصيل nonblocking قراءة باستخدام اسيو؟
-
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.