如何将 boost::asio 与 Linux GPIO 结合使用

2024-05-22

我有一个单线程 Linux 应用程序,使用 boost::asio 进行异步输入/输出。现在我需要扩展此应用程序以读取 GPIO 输入/sys/class/gpio/gpioXX/value.

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

我将 GPIO 输入配置如下:

echo XX >/sys/class/gpio/export
echo in >/sys/class/gpio/gpioXX/direction
echo both >/sys/class/gpio/gpioXX/edge

我设法写了一个epoll基于测试应用程序,该应用程序会阻塞 GPIO 文件描述符,直到 GPIO 信号发生变化,但是boost::asio似乎无法正确阻止。致电boost::asio::async_read总是立即调用处理程序(当然仅在io_service.run()) 与 EOF 或 - 如果文件指针被设置回 - 2 字节数据。

我不是这方面的专家boost::asio内部结构,但原因可能是boost::asioepoll 反应器是电平触发而不是边沿触发posix::stream_descriptor?

这是我的代码:

#include <fcntl.h>

#include <algorithm>
#include <iterator>
#include <stdexcept>

#include <boost/asio.hpp>

boost::asio::io_service io_service;
boost::asio::posix::stream_descriptor sd(io_service);
boost::asio::streambuf streambuf;

void read_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
    if (error.value() == boost::asio::error::eof) {
        // If we don't reset the file pointer we only get EOFs
        lseek(sd.native_handle(), 0, SEEK_SET);
    } else if (error)
        throw std::runtime_error(std::string("Error ") + std::to_string(error.value()) + " occurred (" + error.message() + ")");

    std::copy_n(std::istreambuf_iterator<char>(&streambuf), bytes_transferred, std::ostreambuf_iterator<char>(std::cout));
    streambuf.consume(bytes_transferred);
    boost::asio::async_read(sd, streambuf, &read_handler);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
        return 1;

    int fd = open(argv[1], O_RDONLY);
    if (fd < 1)
        return 1;

    try {
        sd.assign(fd);
        boost::asio::async_read(sd, streambuf, &read_handler);
        io_service.run();
    } catch (...) {
        close(fd);
        return 1;
    }

    close(fd);
    return 0;
}

据我所知,使用 Boost.Asio 不可能获得这种特殊行为。虽然内核将 procfs 和 sysfs 上的某些文件标记为可轮询,但它们不提供预期的类似流的行为boost::asio::posix::stream_descriptor http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/reference/posix__stream_descriptor.html及其运营。

Boost.Asio's epoll reactor is edge-triggered (see Boost.Asio 1.43 revision history notes http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/history.html#boost_asio.history.asio_1_4_5___boost_1_43). Under certain conditions1, Boost.Asio will attempt the I/O operation within the context of the initiating function (e.g. async_read() http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/reference/async_read/overload3.html). If the I/O operation completes (success or failure), then the completion handler is posted into the io_service as-if by io_service.post(). Otherwise, the file descriptor will be added to the event demultiplexer for monitoring. The documentation alludes to this behavior:

无论是否异步操作立即完成无论是否,都不会从此函数内调用处理程序。处理程序的调用将以相当于使用的方式执行boost::asio::io_service::post().

对于组合操作,例如async_read(), EOF 被视为错误 http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/overview/core/streams.html#boost_asio.overview.core.streams.why_eof_is_an_error,因为它表明违反了操作合同(即永远不会满足完成条件,因为没有更多数据可用)。在这种特殊情况下,I/O 系统调用将发生在async_read()启动函数,从文件开头(偏移0)读取到文件末尾,导致操作失败boost::asio::error::eof。当操作完成时,它永远不会添加到事件多路分解器中以进行边沿触发监控:

boost::asio::io_service io_service;
boost::asio::posix::stream_descriptor stream_descriptor(io_service);

void read_handler(const boost::system::error_code& error, ...)
{
  if (error.value() == boost::asio::error::eof)
  {
    // Reset to start of file.
    lseek(sd.native_handle(), 0, SEEK_SET);
  }

  // Same as below.  ::readv() will occur within this context, reading
  // from the start of file to end-of-file, causing the operation to
  // complete with failure.
  boost::asio::async_read(stream_descriptor, ..., &read_handler);
}

int main()
{
  int fd = open( /* sysfs file */, O_RDONLY);

  // This would throw an exception for normal files, as they are not
  // poll-able.  However, the kernel flags some files on procfs and
  // sysfs as pollable.
  stream_descriptor.assign(fd);

  // The underlying ::readv() system call will occur within the
  // following function (not deferred until edge-triggered notification
  // by the reactor).  The operation will read from start of file to
  // end-of-file, causing the operation to complete with failure.
  boost::asio::async_read(stream_descriptor, ..., &read_handler);

  // Run will invoke the ready-to-run completion handler from the above
  // operation.
  io_service.run();
}

1. Internally, Boost.Asio refers to this behavior as speculative operations. It is an implementation detail, but the I/O operation will be attempted within the initiating function if the operation may not need event notification (e.g. it can immediately attempt to a non-blocking I/O call), and and there are neither pending operations of the same type nor pending out-of-band operations on the I/O object. There are no customization hooks to prevent this behavior.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 boost::asio 与 Linux GPIO 结合使用 的相关文章

  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐