zeus_masta_funk zeus_masta_funk - 1 year ago 137
C++ Question

Thread communication using C++14 and GLib (GDBus)

I'm designing a class which will create another object that runs in parallel. This parallel object will run a

GMainLoop
and listen for various events (DBus in this case). My issue is I'm unsure on how to communicate with a thread running in a
GMainLoop
. Am I forced to use the
GLib
methods of communication with that thread? I'd rather rely on the standard library as hopefully I will eventually be able to remove my dependency on
GLib
altogether. Here is a toy example of what I'm trying to accomplish:

// Example program
#include <iostream>
#include <thread>
#include <memory>

#include <glib.h>

class ParallelTask
{
public:
ParallelTask() {
std::cout << "I am alive!\n";

// initialize _mainLoop (allocate, add signals, set priority, etc)
// ...

g_main_loop_run(_mainLoop);
};
~ParallelTask() {
std::cout << "I am dead!\n";

// Misc cleanup
// ...

g_main_loop_quit(_mainLoop);
}
private:
GMainLoop* _mainLoop;
};

class TaskManager
{
public:
TaskManager() = default;
~TaskManager() {join();}

void startTask() {

_thread = std::thread([this](){_task = std::make_unique<ParallelTask>();});
}
void stopTask() {
//??? Need to send message to Parallel task telling it to shut down
join();
}

private:
void join() {
if (_thread.joinable()) {
_thread.join();
}
};

std::thread _thread;
std::unique_ptr<ParallelTask> _task;
};

int main()
{
TaskManager taskManager;
taskManager.startTask();

// Do other stuff

taskManager.stopTask();
}


Additionally, I am running on a Linux based OS. I'd even prefer a
pthread
based solution over a
GLib
one. However, if no other solution is possible, I would gladly take
GLib
suggestions. Thanks!

Answer Source

I've determined that for my needs I can use g_main_context_iteration instead of g_main_loop_run. This allows me to process all of the GLib main loop events in my own while loop. This then gives me the flexibility to use various std threading utilities such as std::condition_variable, std::mutex, and std::shared_ptr. Example of how to use g_main_context_iteration:

#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <chrono>

#include <glib.h>

using namespace std::chrono_literals;

void concurrentTask(std::atomic_bool& process)
{
    std::cout << "Beginning processing\n";

    GMainContext *context = g_main_context_default();

    // Register signals, etc...

    while (process == true)
    {
        g_main_context_iteration(context, false);
    }

    g_main_context_unref(context);
}

int main()
{
    std::atomic_bool process(true);

    std::thread task(concurrentTask, std::ref(process));

    std::this_thread::sleep_for(2s);
    process = false;
    task.join();
    std::cout << "Processing complete\n";
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download