dbus-cxx 阻塞主线程直到DBUS连接断开

问题描述 投票:0回答:1

我正在使用

dbus-cxx
库通过 DBUS 在程序之间进行通信。然而,我感到困惑的一点是,当连接在 server 应用程序上打开时,如何防止主线程退出。

我的第一次尝试是使用无限循环,它会一直循环直到连接不再有效。

大部分复制自 dbus-cxx 快速入门示例

double add(double param1, double param2) { return param1 + param2; }

void TestServer::startServer() {
    std::shared_ptr<DBus::StandaloneDispatcher> dispatcher = DBus::StandaloneDispatcher::create();

    std::shared_ptr<DBus::Connection> conn = dispatcher->create_connection(DBus::BusType::SYSTEM);

    if (conn->request_name("dbuscxx.quickstart_0.server", DBUSCXX_NAME_FLAG_REPLACE_EXISTING) !=
        DBus::RequestNameResponse::PrimaryOwner)
        return;

    // create an object that will contain methods that can be called
    std::shared_ptr<DBus::Object> object =
        conn->create_object("/dbuscxx/quickstart_0", DBus::ThreadForCalling::DispatcherThread);

    // add a method that can be called over the dbus
    object->create_method<double(double, double)>("dbuscxx.Quickstart", "add", sigc::ptr_fun(add));

    while (conn->is_valid()) {
    }

    SPDLOG_INFO("Connection status {0}", conn->is_valid());
}

但是我觉得这样效率确实很低,而且浪费CPU资源。我在网上看到的一种替代方法是在线程中设置睡眠,这样它只会偶尔检查:

while (conn->is_valid()) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

我阅读的最好方法是使用

thread::join
,但是,dbus-cxx 库不允许我访问调度程序或连接正在运行的线程,因此我无法调用 join它。我也没有找到可以调用
wait
conditional_variable

我能够使用以下命令获取我认为的连接的文件描述符(不确定,但我认为它是到 DBUS 的管道):

conn->unix_fd();

但我不知道如何使用它来确定集合何时关闭。我可以在连接中使用 unix_fd 吗?


所以我的问题是,无需重写任何 dbus-cxx 文件,如何阻塞主线程直到连接关闭(以一种效率不是非常低的方式)?

(顺便说一句,对于服务来说,具有 1 秒睡眠的无限循环是否“足够好”?还是效率极低?)

任何见解将不胜感激,这是我第一次处理多线程和使用复杂的库。 :)

c++ multithreading pthreads infinite-loop dbus
1个回答
0
投票

好吧,我想我有一个解决方案,但我愿意接受其他可能更好的答案:


int DBus::Connection::unix_fd()
是一个返回用于与主 dbus 服务通信的流的文件描述符的函数。

在我们的代码中,我们可以使用 Linux

poll(...)
函数,而不是无限的 while 循环,该函数将阻塞我们的代码,直到
pollfd
结构中定义的某个指定事件为止。

根据Linux手册页的

poll
功能:

字段事件是一个输入参数,一个指定事件的位掩码 应用程序对文件描述符感兴趣的事件 FD。 该字段可以指定为零,在这种情况下唯一的 可以在 revents 中返回的事件有 POLLHUP、POLLERR 和 POLLNVAL(见下文)。

民意调查 挂断(仅在 revents 中返回;在事件中被忽略)。 请注意,从管道或管道等通道读取数据时 流套接字,此事件仅表明对等方 关闭了通道的末端。随后读取来自 毕竟通道只会返回 0(文件结尾) 通道中未完成的数据已被消耗。

轮询 错误条件(仅在 revents 中返回;在 事件)。该位也为文件描述符设置 当读端有时指管道的写端 已关闭。

民意调查 无效请求:fd未打开(仅在revents中返回; 在事件中被忽略)。

这非常适合我想要的!

现在我们的阻止代码如下所示:

auto fd = conn->unix_fd();

pollfd fds;
fds.fd = fd;
fds.events = 0;
poll(&fds, 1, -1); // this should (hopefully) block the thread until fd is closed

这样做的好处是,在文件描述符关闭或抛出错误之前,内核不会将 CPU 周期专用于主线程。这使其成为满足我需求的完美、最有效的解决方案。

希望这对将来的人有帮助:)

© www.soinside.com 2019 - 2024. All rights reserved.