C++ asio::读取超时

C++ asio::读取超时,c++,boost,timeout,serial-port,boost-asio,C++,Boost,Timeout,Serial Port,Boost Asio,我需要知道如何在超时的情况下读取(同步或异步不重要)。我想检查设备是否与串行端口连接 为此,我使用asio::write,然后等待设备的响应 如果连接了设备asio::read(串行,boost::asio::buffer(&r,1))工作正常,但如果没有设备,程序将停止,这就是我需要超时的原因 我知道我需要一个截止时间计时器,但我不知道如何在异步读取功能中使用它 template <typename SyncReadStream, typename MutableBufferSequen

我需要知道如何在超时的情况下读取(同步或异步不重要)。我想检查设备是否与串行端口连接

为此,我使用
asio::write
,然后等待设备的响应

如果连接了设备
asio::read(串行,boost::asio::buffer(&r,1))
工作正常,但如果没有设备,程序将停止,这就是我需要超时的原因

我知道我需要一个
截止时间计时器
,但我不知道如何在
异步读取
功能中使用它

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);
}
举个例子来说明它是如何工作的,这将非常有帮助

我知道有许多类似的线程,我读了很多,但我找不到一个解决方案,帮助我解决我的问题

从本质上来说,没有一个简单的答案,因为即使您进行异步读取,也永远不会调用回调,而且您现在的周围有一个松散的线程

您正确地认为,
deadline\u timer
是可能的解决方案之一,但它需要一些处理和共享状态。这里有一个问题,但这是针对
异步连接的,当它没事做时,它返回有一件很酷的事情<代码>读取
不会这样做,最坏的情况是——它会因为无效资源而崩溃并烧掉。因此,
截止时间计时器
是您的选择之一,但实际上有一个更简单的选项,有点像这样:

boost::thread *newthread = new boost::thread(boost::bind(&::try_read));
if (!newthread->timed_join(boost::posix_time::seconds(5))) {
    newthread->interrupt();
}
基本上,在另一个线程中进行读取,并在超时时将其杀死。你应该仔细阅读


如果中断,请确保所有资源都已关闭。

async\u read
中不要使用
截止时间计时器。但您可以启动两个异步进程:

  • 串行端口上的
    异步读取
    进程。具有取消其上所有异步操作的方法
  • 具有所需超时的截止时间计时器。在
    deadline\u timer的完成处理程序中
    可以
    取消
    串行端口。这将关闭
    async\u read
    操作,并调用其完成处理程序,但出现错误
  • 代码:

    #包括
    #包括
    #包括
    #包括
    #包括
    类定时连接
    {
    公众:
    定时连接(int超时):
    计时器(io_服务,boost::posix_时间::秒(超时)),
    串行端口(io服务)
    {
    }
    void start()
    {
    计时器\异步\等待
    (
    boost::bind
    (
    &定时连接::停止,这是
    )
    );
    //连接插座
    //写入套接字
    //从串行端口异步读取
    boost::asio::异步读取
    (
    串行端口,boost::asio::buffer(缓冲区),
    boost::bind
    (
    &定时连接::句柄读取,此,
    boost::asio::占位符::错误
    )
    );
    io_服务_uu.run();
    }
    私人:
    无效停止()
    {  
    串行端口取消();
    }
    无效句柄读取(const boost::system::error\u code&ec)
    {  
    国际单项体育联合会(欧共体)
    {  
    //处理错误
    }
    其他的
    {  
    //做点什么
    }
    }
    私人:
    boost::asio::io_服务io_服务;
    boost::asio::截止时间\u计时器\uu;
    boost::asio::串行端口串行端口;
    boost::数组缓冲区;
    };
    int main()
    {
    定时_连接接头(5);
    连接开始();
    返回0;
    }
    
    有一次,库作者提出了以下方法(本例涉及
    tcp::socket
    ,但您可以使用串行端口):

    void set_结果(可选*a,错误代码b)
    { 
    a->重置(b);
    } 
    模板
    无效读取超时的\u(tcp::socket和sock,
    常量可变缓冲区序列和缓冲区)
    { 
    可选的定时器输出结果;
    截止期计时器(sock.io_service());
    timer.expires_from_now(秒(1));
    异步等待(boost::bind(set_result,&timer_result,_1));
    可选的读取结果;
    异步读取(sock、缓冲区、,
    boost::bind(set_result,&read_result,_1));
    sock.io_service().reset();
    while(sock.io_service().run_one())
    { 
    如果(读取结果)
    timer.cancel();
    else if(计时器\u结果)
    sock.cancel();
    } 
    如果(*读取结果)
    抛出系统错误(*读取结果);
    } 
    
    没有为我编译。这是我对他的代码的改进版本,它工作得非常好。它使用lambdas来摆脱
    set\u result
    helper函数

    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);
    }
    
    模板
    void readWithTimeout(SyncReadStream&s、const MutableBufferSequence&buffers、const boost::asio::deadline\u timer::duration\u type和Expiration\u time)
    {
    boost::可选的定时器结果;
    boost::asio::deadline_timer(s.get_io_service());
    timer.expires\u from\u now(expire\u time);
    timer.async_wait([&timer_result](const boost::system::error_code&error){timer_result.reset(error);});
    boost::可选的读取结果;
    boost::asio::async_read(s,buffers,[&read_result](const boost::system::error_code&error,size_t){read_result.reset(error);});
    s、 获取io_服务().reset();
    而(s.get_io_service().run_one())
    { 
    如果(读取结果)
    timer.cancel();
    else if(计时器\u结果)
    s、 取消();
    }
    如果(*读取结果)
    抛出boost::system::system\u错误(*读取结果);
    }
    
    问题明确说明他使用的是串行设备,而不是TCP端点。如果他使用*nix,UNIX套接字可能是一个选项,但是操作系统没有声明,它们破坏了可移植性。@TC1,当然,编辑了代码。从概念上讲,Asio抽象它的方式没有任何变化。你确定Asio i/o操作是一个中断点吗?有人能够证实这一点吗?这能解决问题吗
    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);
    }