如何将成员函数传递给 g_source_set_callback?

How do I pass member functions to g_source_set_callback?

我正在尝试将成员函数指针传递给 g_source_set_callback 以将它们排队。这是我写的伪代码。

#include<glib.h>

#include<iostream>
#include<thread>
#include<chrono>

using namespace std;
using namespace std::chrono_literals;

class executor
{
private:
    GMainLoop* main_loop;
    GMainContext* worker_context;
    thread worker_thread;

    void worker_loop()
    {
        g_main_context_push_thread_default(worker_context);
        cout << "Starting main loop" << endl;
        g_main_loop_run(main_loop);
        cout << "Finished main loop" << endl;
        g_main_context_pop_thread_default(worker_context);
    }

    void queue_callback(int (*callback)(void))
    {
        GSource* idle_source = g_idle_source_new();
        g_source_set_callback(idle_source, (GSourceFunc)callback, NULL, NULL);
        g_source_attach(idle_source, worker_context);
        g_source_unref(idle_source);
    }


    int func1()
    {
        cout << "func1 started" << endl;
        this_thread::sleep_for(5s);
        cout << "func1 finished waiting" << endl;
        return 0;
    }

    int func2()
    {
        cout << "func2 started" << endl;
        this_thread::sleep_for(1s);
        cout << "func2 finished waiting" << endl;
        return 0;
    }

public:
    executor()
    {
        worker_context = g_main_context_new();
        main_loop = g_main_loop_new(worker_context, false);
        worker_thread = thread(&executor::worker_loop, this);
    }

    ~executor()
    {
        cout << "Stopping main loop" << endl;
        GSource* idle_source = g_idle_source_new();
        g_source_set_callback(idle_source, (GSourceFunc)g_main_loop_quit, main_loop, NULL);
        g_source_attach(idle_source, worker_context);
        g_source_unref(idle_source);

        if (worker_thread.joinable())
        {
            worker_thread.join();
        }
        cout << "Removing references to main loop and context" << endl;

        g_main_loop_unref(main_loop);
        g_main_context_unref(worker_context);
    }

    void start()
    {
        queue_callback(func1);
        queue_callback(func2);
    }
};

int main()
{
    executor e;
    e.start();
    return 0;
}

我知道你不能像那样传递非静态成员函数,所以,我得到了预期的编译错误。

test.cpp: In member function ‘void executor::start()’:
test.cpp:79:37: error: invalid use of non-static member function ‘int executor::func1()’
                 queue_callback(func1);
                                     ^
test.cpp:35:13: note: declared here
         int func1()
             ^~~~~
test.cpp:80:37: error: invalid use of non-static member function ‘int executor::func2()’
                 queue_callback(func2);
                                     ^
test.cpp:43:13: note: declared here
         int func2()
             ^~~~~

我看到有人用函数对象来包装成员函数。所以,我尝试了这个。

#include<glib.h>

#include<iostream>
#include<thread>
#include<chrono>
#include<functional>

using namespace std;
using namespace std::chrono_literals;

class executor
{
private:
    GMainLoop* main_loop;
    GMainContext* worker_context;
    thread worker_thread;

    void worker_loop()
    {
        g_main_context_push_thread_default(worker_context);
        cout << "Starting main loop" << endl;
        g_main_loop_run(main_loop);
        cout << "Finished main loop" << endl;
        g_main_context_pop_thread_default(worker_context);
    }

    void queue_callback(const function<int()>* callback)
    {
        GSource* idle_source = g_idle_source_new();
        g_source_set_callback(idle_source, reinterpret_cast<GSourceFunc>(&on_callback), const_cast<function<int()>*>(callback), NULL);
        g_source_attach(idle_source, worker_context);
        g_source_unref(idle_source);
    }

    static int on_callback(const function<int()>* callback)
    {
        return (*callback)();
    }

    int func1()
    {
        cout << "func1 started" << endl;
        this_thread::sleep_for(5s);
        cout << "func1 finished waiting" << endl;
        return 0;
    }

    int func2()
    {
        cout << "func2 started" << endl;
        this_thread::sleep_for(1s);
        cout << "func2 finished waiting" << endl;
        return 0;
    }

public:
    executor()
    {
        worker_context = g_main_context_new();
        main_loop = g_main_loop_new(worker_context, false);
        worker_thread = thread(&executor::worker_loop, this);
    }

    ~executor()
    {
        cout << "Stopping main loop" << endl;
        GSource* idle_source = g_idle_source_new();
        g_source_set_callback(idle_source, (GSourceFunc)g_main_loop_quit, main_loop, NULL);
        g_source_attach(idle_source, worker_context);
        g_source_unref(idle_source);

        if (worker_thread.joinable())
        {
            worker_thread.join();
        }
        cout << "Removing references to main loop and context" << endl;

        g_main_loop_unref(main_loop);
        g_main_context_unref(worker_context);
    }

    void start()
    {
        cout << "Submitting func1 callback" << endl;
        function<int()> callback1 = [this]() {
            return func1();
        };
        queue_callback(&callback1);

        cout << "Submitting func2 callback" << endl;
        function<int()> callback2 = [this]() {
            return func2();
        };
        queue_callback(&callback2);
    }
};

int main()
{
    executor e;
    e.start();
    return 0;
}

这段代码可以编译,但我总是遇到分段错误或 bad_function_call 异常。

Starting main loop
Submitting func1 callback
Submitting func2 callback
Stopping main loop
func1 started
func1 finished waiting
terminate called after throwing an instance of 'std::bad_function_call'
  what():  bad_function_call
Aborted (core dumped)

我想我收到了错误,因为 callback1callback2 是本地对象,当它们被执行时,它们的内存已被释放。

我该如何解决这个问题?我想过使用 unique_ptrs,但无法弄清楚 g_source_set_callback 如何将 int (*GSourceFunc) void 作为第二个参数,将 void* 作为第三个参数。

我明白了。 我创建了一个新的 std::function 对象并将其传递给 g_source_set_callback。当调用 on_callback 时,我将 void * 类型转换为 std::function<int()>*,调用它并删除它。 这是工作代码。

#include<glib.h>

#include<iostream>
#include<thread>
#include<chrono>
#include<functional>

using namespace std;
using namespace std::chrono_literals;

class executor
{
private:
    GMainLoop* main_loop;
    GMainContext* worker_context;
    thread worker_thread;

    void worker_loop()
    {
        g_main_context_push_thread_default(worker_context);
        cout << "Starting main loop" << endl;
        g_main_loop_run(main_loop);
        cout << "Finished main loop" << endl;
        g_main_context_pop_thread_default(worker_context);
    }

    void queue_callback(function<int()>&& callback)
    {
        GSource* idle_source = g_idle_source_new();
        g_source_set_callback(idle_source, on_callback, new function<int()>(callback), NULL);
        g_source_attach(idle_source, worker_context);
        g_source_unref(idle_source);
    }

    static int on_callback(void* ptr)
    {
        function<int()>* callback = static_cast<function<int()>*>(ptr);
        int ret = (*callback)();
        delete callback;
        return ret;
    }

    int func1()
    {
        cout << "func1 started" << endl;
        this_thread::sleep_for(5s);
        cout << "func1 finished waiting" << endl;
        return 0;
    }

    int func2()
    {
        cout << "func2 started" << endl;
        this_thread::sleep_for(1s);
        cout << "func2 finished waiting" << endl;
        return 0;
    }

public:
    executor()
    {
        worker_context = g_main_context_new();
        main_loop = g_main_loop_new(worker_context, false);
        worker_thread = thread(&executor::worker_loop, this);
    }

    ~executor()
    {
        cout << "Stopping main loop" << endl;
        GSource* idle_source = g_idle_source_new();
        g_source_set_callback(idle_source, (GSourceFunc)g_main_loop_quit, main_loop, NULL);
        g_source_attach(idle_source, worker_context);
        g_source_unref(idle_source);

        if (worker_thread.joinable())
        {
            worker_thread.join();
        }
        cout << "Removing references to main loop and context" << endl;

        g_main_loop_unref(main_loop);
        g_main_context_unref(worker_context);
    }

    void start()
    {
        cout << "Submitting func1 callback" << endl;
        queue_callback([this]() { return func1(); });

        cout << "Submitting func2 callback" << endl;
        queue_callback([this]() { return func2(); });
    }
};

int main()
{
    executor e;
    e.start();
    return 0;
}