2012-10-29 33 views
10

के साथ पढ़ें मुझे टाइमआउट के साथ पढ़ने (सिंक या एसिंक कोई फर्क नहीं पड़ता) को जानने की आवश्यकता है। मैं यह जांचना चाहता हूं कि कोई डिवाइस सीरियल पोर्ट से कनेक्ट है या नहीं।asio :: टाइमआउट

इसके लिए मैं asio::write का उपयोग करता हूं और फिर मैं डिवाइस की प्रतिक्रिया के लिए प्रतीक्षा करता हूं।

एक डिवाइस कनेक्ट asio::read(serial, boost::asio::buffer(&r,1)) है, तो ठीक काम करता है, लेकिन कोई डिवाइस कार्यक्रम बंद हो जाता है, जो वहाँ है अगर कारण है कि मैं समय समाप्ति की जरूरत

मुझे पता है कि मैं एक deadline_timer की जरूरत है, लेकिन मैं यह कैसे उपयोग करने के लिए पता नहीं है async_read फ़ंक्शन में।

यह कैसे काम करता है इसका एक उदाहरण वास्तव में सहायक होगा।

मुझे पता है कि कई समान धागे हैं और मैंने उनमें से बहुत कुछ पढ़ा है लेकिन मुझे कोई समाधान नहीं मिल रहा है जो मेरी समस्या को हल करने में मेरी सहायता करता है!

उत्तर

0

कोई भी या आसान उत्तर प्रति से है, क्योंकि यदि आप एसिंक पढ़ते हैं, तो भी कॉलबैक कभी नहीं बुलाया जाता है और अब आपके पास कहीं ढीला धागा है।

आप यह मानने में सही हैं कि deadline_timer संभावित समाधानों में से एक है, लेकिन यह कुछ विचित्र और साझा राज्य लेता है। blocking TCP example है, लेकिन यह async_connect के लिए है और इसके बारे में कुछ भी नहीं है जब इसे वापस करने के लिए कुछ भी नहीं है। read ऐसा नहीं करेगा, सबसे खराब स्थिति परिदृश्य - यह & अमान्य संसाधन का कारण 'बर्बाद कर देगा। तो deadline timer बात अपने विकल्पों में से एक है, लेकिन वहाँ वास्तव में एक आसान एक है, कि इस तरह कुछ हद तक चला जाता है है:

boost::thread *newthread = new boost::thread(boost::bind(&::try_read)); 
if (!newthread->timed_join(boost::posix_time::seconds(5))) { 
    newthread->interrupt(); 
} 

मूल रूप से, एक और धागा में पढ़ा करते हैं और इसे अगर यह समय समाप्त बंद मार डालते हैं। आपको Boost.Threads पर पढ़ना चाहिए।

यदि आप इसे बाधित करते हैं, तो सुनिश्चित करें कि संसाधन बंद हैं।

+3

क्या आप सुनिश्चित हैं कि asio i/o ऑपरेशन एक बाधा बिंदु है? –

+0

क्या कोई यह पुष्टि करने में सक्षम है? क्या यह समाधान काम करता है? – rustyx

+0

मैंने इसका परीक्षण किया है, मेरे लिए काम नहीं किया है। बाधा एएसओ I/o ऑपरेशन के दौरान थ्रेड को रोक नहीं पाएगी। – risingDarkness

5

आप deadline_timerasync_read में उपयोग नहीं करते हैं। लेकिन आप दो एसिंक प्रक्रियाओं को शुरू कर सकते हैं:

  1. सीरियल पोर्ट पर async_read प्रक्रिया। boost::asio::serial_port में cancel विधि है जो इस पर सभी एसिंक ऑपरेशंस को रद्द कर देती है।
  2. आवश्यक समय समाप्ति के साथ एक समय सीमा टाइमर। deadline_timer के लिए पूरा करने वाले हैंडलर में आप cancel सीरियल पोर्ट कर सकते हैं। इसे async_read ऑपरेशन को बंद करना चाहिए और एक त्रुटि के साथ अपना पूरा करने वाले हैंडलर को कॉल करना चाहिए।

कोड:

#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 
#include <boost/array.hpp> 

class timed_connection 
{ 
    public: 
     timed_connection(int timeout) : 
      timer_(io_service_, boost::posix_time::seconds(timeout)), 
      serial_port_(io_service_) 
     { 
     } 

     void start() 
     { 
       timer_.async_wait 
       (
       boost::bind 
       (
        &timed_connection::stop, this 
       ) 
       ); 

      // Connect socket 
      // Write to socket 

      // async read from serial port 
      boost::asio::async_read 
       (
       serial_port_, boost::asio::buffer(buffer_), 
       boost::bind 
       (
        &timed_connection::handle_read, this, 
        boost::asio::placeholders::error 
       ) 
       ); 

      io_service_.run(); 
     } 

    private: 
     void stop() 
     { 
      serial_port_.cancel(); 
     } 

     void handle_read (const boost::system::error_code& ec) 
     { 
      if(ec) 
      { 
       // handle error 
      } 
      else 
      { 
       // do something 
      } 
     } 

    private: 
     boost::asio::io_service io_service_; 
     boost::asio::deadline_timer timer_; 
     boost::asio::serial_port serial_port_; 
     boost::array< char, 8192 > buffer_; 
}; 

int main() 
{ 
    timed_connection conn(5); 
    conn.start(); 

    return 0; 
} 
+1

प्रश्न ** स्पष्ट रूप से ** कहता है कि वह एक सीरियल डिवाइस का उपयोग करता है, न कि टीसीपी एंडपॉइंट। यूनिक्स सॉकेट एक विकल्प हो सकता है यदि उसने * निक्स का उपयोग किया, लेकिन ओएस नहीं कहा गया है और वे ब्रेक पोर्टेबिलिटी की तरह हैं। – TC1

+1

@ टीसी 1, निश्चित रूप से, कोड संपादित किया। संकल्पनात्मक रूप से Asio इसे सार तत्वों, कुछ भी नहीं बदलता है। – Vikas

5
एक समय की बात

, पुस्तकालय लेखक निम्नलिखित तरीके to read synchronously with timeout प्रस्तावित (इस उदाहरण tcp::socket शामिल है, लेकिन आप के बजाय सीरियल पोर्ट का उपयोग कर सकते हैं):

void set_result(optional<error_code>* a, error_code b) 
    { 
    a->reset(b); 
    } 


    template <typename MutableBufferSequence> 
    void read_with_timeout(tcp::socket& sock, 
     const MutableBufferSequence& buffers) 
    { 
    optional<error_code> timer_result; 
    deadline_timer timer(sock.io_service()); 
    timer.expires_from_now(seconds(1)); 
    timer.async_wait(boost::bind(set_result, &timer_result, _1)); 


    optional<error_code> read_result; 
    async_read(sock, buffers, 
     boost::bind(set_result, &read_result, _1)); 

    sock.io_service().reset(); 
    while (sock.io_service().run_one()) 
    { 
     if (read_result) 
     timer.cancel(); 
     else if (timer_result) 
     sock.cancel(); 
    } 


    if (*read_result) 
     throw system_error(*read_result); 
    } 
+0

मुझे तकनीक समझ में नहीं आ रही है। हो सकता है कि यह एक थ्रेडेड परिदृश्य में काम करता है जब कोई अन्य एसिंक ऑपरेशन नहीं हो रहा है। क्या लूप समाप्त हो जाता है? यदि आसपास के अन्य धागे हैं, तो io_service.reset() को एक सुरक्षित चीज़ कह रही है? –

+0

@ टॉम क्वारेन्डन मुझे लगता है कि आप सही हैं, यह काम नहीं करेगा यदि एकाधिक थ्रेड io_service चला रहे हैं। ध्यान दें कि कोई io_service-per-core मॉडल का उपयोग कर सकता है, जहां प्रति io_service पर एक थ्रेड है। –

7

code posted by Igor R. मेरे लिए संकलित नहीं किया था। यहां उनके कोड का मेरा बेहतर संस्करण है, जो पूरी तरह से काम करता है। यह set_result सहायक कार्य से छुटकारा पाने के लिए लैम्बडा का उपयोग करता है।

template <typename SyncReadStream, typename MutableBufferSequence> 
void readWithTimeout(SyncReadStream& s, const MutableBufferSequence& buffers, const boost::asio::deadline_timer::duration_type& expiry_time) 
{ 
    boost::optional<boost::system::error_code> timer_result; 
    boost::asio::deadline_timer timer(s.get_io_service()); 
    timer.expires_from_now(expiry_time); 
    timer.async_wait([&timer_result] (const boost::system::error_code& error) { timer_result.reset(error); }); 

    boost::optional<boost::system::error_code> read_result; 
    boost::asio::async_read(s, buffers, [&read_result] (const boost::system::error_code& error, size_t) { read_result.reset(error); }); 

    s.get_io_service().reset(); 
    while (s.get_io_service().run_one()) 
    { 
     if (read_result) 
      timer.cancel(); 
     else if (timer_result) 
      s.cancel(); 
    } 

    if (*read_result) 
     throw boost::system::system_error(*read_result); 
} 
+0

यह 'boost :: asio :: async_read' के लिए टाइमआउट अनुकरण करने के लिए उत्कृष्ट काम करता है। समस्या के लिए वास्तव में सरल और ठोस दृष्टिकोण। मुझे यह सरल तकनीक पसंद है और मैं इसे 'boost :: asio :: async_write' केस के लिए अनुकूलित करना चाहता हूं? लेकिन यह लिखने के मामले के लिए काम नहीं कर रहा है। क्या आप [इस सवाल पर] [https://stackoverflow.com/questions/47378022/how-to-do-a-boostasioasync-write-with-timeout) पर एक नज़र डालेंगे? –

संबंधित मुद्दे