c – 如何在Linux GPIO中使用boost :: asio

前端之家收集整理的这篇文章主要介绍了c – 如何在Linux GPIO中使用boost :: asio前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个使用boost :: asio进行异步输入/输出的单线程 Linux应用程序.现在我需要扩展此应用程序以读取/ sys / class / gpio / gpioXX / value上的GPIO输入.

在边沿触发的GPIO输入上使用boost :: asio :: posix :: stream_descriptor可以做到这一点吗?

我配置了GPIO输入,如下所示:

  1. echo XX >/sys/class/gpio/export
  2. echo in >/sys/class/gpio/gpioXX/direction
  3. echo both >/sys/class/gpio/gpioXX/edge

我设法写了一个基于epoll的测试应用程序,它阻止GPIO文件描述符,直到GPIO信号改变但boost :: asio似乎无法正常阻塞.对boost :: asio :: async_read的调用总是立即调用处理程序(当然只在io_service.run()中)和EOF或 – 如果文件指针被设置回 – 2字节数据.

我不是boost :: asio内部的专家,但原因可能是在:: posix :: stream_descriptor的情况下,boost :: asio epoll reactor是水平触发而不是边缘触发?

这是我的代码

  1. #include <fcntl.h>
  2.  
  3. #include <algorithm>
  4. #include <iterator>
  5. #include <stdexcept>
  6.  
  7. #include <boost/asio.hpp>
  8.  
  9. boost::asio::io_service io_service;
  10. boost::asio::posix::stream_descriptor sd(io_service);
  11. boost::asio::streambuf streambuf;
  12.  
  13. void read_handler(const boost::system::error_code& error,std::size_t bytes_transferred)
  14. {
  15. if (error.value() == boost::asio::error::eof) {
  16. // If we don't reset the file pointer we only get EOFs
  17. lseek(sd.native_handle(),SEEK_SET);
  18. } else if (error)
  19. throw std::runtime_error(std::string("Error ") + std::to_string(error.value()) + " occurred (" + error.message() + ")");
  20.  
  21. std::copy_n(std::istreambuf_iterator<char>(&streambuf),bytes_transferred,std::ostreambuf_iterator<char>(std::cout));
  22. streambuf.consume(bytes_transferred);
  23. boost::asio::async_read(sd,streambuf,&read_handler);
  24. }
  25.  
  26. int main(int argc,char *argv[])
  27. {
  28. if (argc != 2)
  29. return 1;
  30.  
  31. int fd = open(argv[1],O_RDONLY);
  32. if (fd < 1)
  33. return 1;
  34.  
  35. try {
  36. sd.assign(fd);
  37. boost::asio::async_read(sd,&read_handler);
  38. io_service.run();
  39. } catch (...) {
  40. close(fd);
  41. return 1;
  42. }
  43.  
  44. close(fd);
  45. return 0;
  46. }

解决方法

据我所知,使用Boost.Asio无法获得这种特殊行为.虽然内核将procfs和sysfs上的某些文件标记为可轮询,但它们不提供 boost::asio::posix::stream_descriptor及其操作所期望的类似流的行为.

Boost.Asio的epoll反应器是边缘触发的(参见Boost.Asio 1.43 revision history notes).在某些条件下1,Boost.Asio将在启动功能的上下文中尝试I / O操作(例如async_read()).如果I / O操作完成(成功或失败),则完成处理程序将按照io_service.post()发布到io_service中.否则,文件描述符将被添加到事件多路分解器以进行监视.该文档暗示了这种行为:

Regardless of whether the asynchronous operation completes immediately or not,the handler will not be invoked from within this function. Invocation of the handler will be performed in a manner equivalent to using boost::asio::io_service::post().

对于组合操作,例如async_read(),EOF is treated as an error,因为它表示操作合同中存在违规(即永远不会满足完成条件,因为没有更多数据可用).在这种特殊情况下,I / O系统调用将在async_read()启动函数中发生,从文件的开头(偏移0)读取到文件的末尾,导致操作失败,使用boost :: asio ::错误:: EOF.操作完成后,它永远不会添加到事件多路分解器中以进行边缘触发监视:

  1. boost::asio::io_service io_service;
  2. boost::asio::posix::stream_descriptor stream_descriptor(io_service);
  3.  
  4. void read_handler(const boost::system::error_code& error,...)
  5. {
  6. if (error.value() == boost::asio::error::eof)
  7. {
  8. // Reset to start of file.
  9. lseek(sd.native_handle(),SEEK_SET);
  10. }
  11.  
  12. // Same as below. ::readv() will occur within this context,reading
  13. // from the start of file to end-of-file,causing the operation to
  14. // complete with failure.
  15. boost::asio::async_read(stream_descriptor,...,&read_handler);
  16. }
  17.  
  18. int main()
  19. {
  20. int fd = open( /* sysfs file */,O_RDONLY);
  21.  
  22. // This would throw an exception for normal files,as they are not
  23. // poll-able. However,the kernel flags some files on procfs and
  24. // sysfs as pollable.
  25. stream_descriptor.assign(fd);
  26.  
  27. // The underlying ::readv() system call will occur within the
  28. // following function (not deferred until edge-triggered notification
  29. // by the reactor). The operation will read from start of file to
  30. // end-of-file,causing the operation to complete with failure.
  31. boost::asio::async_read(stream_descriptor,&read_handler);
  32.  
  33. // Run will invoke the ready-to-run completion handler from the above
  34. // operation.
  35. io_service.run();
  36. }

在内部,Boost.Asio将此行为称为推测性操作.这是一个实现细节,但如果操作可能不需要事件通知(例如,它可以立即尝试非阻塞I / O调用),则将在启动函数内尝试I / O操作,并且既没有挂起I / O对象上的相同类型的操作或未决的带外操作.没有自定义挂钩来防止此行为.

猜你在找的C&C++相关文章