正确处理从线程中迭代的 NetworkManager 对象获取的 GMainContext

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

我正在尝试使用

libnm
库从一个线程调用 NetworkManager 调用,而另一个线程则负责迭代上下文并处理异步方法的回调。然而,无论我做什么,我似乎都无法摆脱这三个关键的
glib
警告:

GLib-CRITICAL **: 15:55:38.490: g_main_context_push_thread_default: assertion 'acquired_context' failed

GLib-CRITICAL **: 15:55:38.490: g_main_context_pop_thread_default: assertion 'g_queue_peek_head (stack) == context' failed

libnm-CRITICAL **: 15:55:38.491: ((libnm/nm-client.c:5925)): assertion '<dropped>' failed

我做了一个最低限度可重复的例子,如下所示

#include <thread>
#include <glib.h>
#include <gio/gio.h>
#include <iostream>
#include <NetworkManager.h>

class NetworkManager
{
public:
    NetworkManager()
    {
        std::cout << "Network manager creation" << std::endl;
        GError* error;
        m_client = nm_client_new(nullptr, &error);
        m_context = nm_client_get_main_context(m_client);
        m_thread = std::thread([this]() {
            g_main_context_push_thread_default(m_context);
            while (true)
            {
                g_main_context_iteration(m_context, true);
            }
            g_main_context_pop_thread_default(m_context);
        });
        std::this_thread::sleep_for(std::chrono::seconds(1));
        nm_client_reload_connections_async(m_client, nullptr, (GAsyncReadyCallback)callback, this);
    }
    ~NetworkManager() {};
    static void callback(GObject*, GAsyncResult*, gpointer data)
    {
        auto nm_ptr = static_cast<NetworkManager*>(data);
        bool success = nm_client_reload_connections_finish(nm_ptr->m_client, nullptr, nullptr);
        std::cout << success << std::endl;
    }
    std::thread m_thread;
    GMainContext* m_context;
    NMClient* m_client;
};


int main() {
    NetworkManager nm{};
    int i = 0;
    while(true)
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::cout << i++ << std::endl;
    }
}

我是否误解了主上下文线程推送和弹出的工作原理?我已经阅读了 Main Context 教程,但我仍然不完全理解如何从另一个线程正确处理主上下文。

c++ multithreading glib networkmanager
1个回答
0
投票

libnm 为您提供

NMClient
。这是您在 D-Bus API 上看到的数据的客户端缓存。

该缓存本身不是线程安全的。 ...嗯,它是线程安全的,因为每次通过它的访问都必须经过关联的

GMainContext

您无法从多个线程访问数据。除非,您确保他们不会同时访问数据。确保这一点的建议方法是在访问之前获取 GMainContext。

通常,每个线程都有一个 GMainContext。但您也可以在线程之间传递一个 GMainContext。但话虽如此,您仍然必须在访问数据之前获取上下文。这里的“获取”是指获得独占访问权。如果你做一些不平凡的事情,你就需要提防死锁。

也许您应该只让一个线程运行 GMainContext 并访问 NMClient。然后在线程之间传递数据(例如,通过使用

g_idle_source_new()
在其他线程中附加回调)。

你会得到断言失败,因为

g_main_context_iteration()
将获取GMainContext。另一个线程无法再次获取它,并且尝试以这种方式使用 NMClient 会失败。

我建议再读一遍教程。 IMO 非常好。

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