kamilm
kamilm

Reputation: 141

Scheduling a worker job and receiving a callback in the main thread in C++

In my current code I have a solution that allows the main thread to schedule some job to be asynchronusly executed in the worker thread.

When the worker thread is finished, it is supposed to notify the main thread using the supplied callback function. The main problem is that I want this callback to be executed in the main thread instead of the worker thread, so simple function call from the worker after it finishes its job is not an option (callback performs some application logic that may be quite complex and I don't want the worker thread to be busy with that).

I have a legacy solution for that problem (using events to signal the main thread that the job was completed etc.), but I'm looking for some general and reusable solution - is there anything in C++ that I can use?

Ideally I'm looking for a solution like boost::signals, but as far as I understood that is not thread-aware. Any ideas?

EDIT: final solution must work on linux and be compiled with GCC

EDIT2: some example code added

Typical usage of callbacks may look like this (this won't compile, but I wanted to keep it simple to show the general idea):

///////// main thread ////////////

void fun() { /* work to be done in worker thread */ }

void callback() { /* callback that will be called when fun() is done */ }

int main() {
    Worker worker;
    worker.doAsync(fun, callback);
    // waiting for the worker to finish the job
}

////// worker thread code ///////

/// main worker loop
void Worker::run() {
    // wait until the task is scheduled 

    // run the scheduled tasks
    fun();
    // when task was finished, call the callback
    callback();
}

The problem with the above code is that callback() function will be called from the worker thread - what I want is to have the worker thread signal the main thread that the job is done and the main thread should now call the callback because the job was done.

Upvotes: 2

Views: 2072

Answers (3)

Cumatru
Cumatru

Reputation: 725

You can use callback as a wrapper for mainThreadCallback

Create mainThreadCallback

gboolean mainThreadCallback(gpointer data)
{
    //cast data to whatever you need
    return FALSE; // so it will run only once
}

Inside

void callback()
{
   g_idle_add ((GSourceFunc) mainThreadCallback, NULL /* custom data */);
}

The function mainThreadCallback will run in the main thread as soon as it will be available. You will need to have a GMainLoop inside your int main() function.

Upvotes: 0

triple_r
triple_r

Reputation: 1047

If your worker is going to return a value, use future, otherwise, you can just spawn the workers and tell the main thread to wait for them to finish by threadxxx.join(). Here are two examples:

with threads:

#include <thread>

int main()
{
    std::thread thread1(fun);
    //anything here will be run simultaneously
    ...
    thread1.join();
    //anything here will be run after thread1 is done
    return 0;
}

with future:

#include <future>
#include <thread>

int main()
{
    std::future<double> future1 = std::async(std::launch::async, fun());
    //anything here will run simultaneously;
    ...
    //get() will wait for the result, if the thread is not done yet.
    double res = future1.get();
    //from here on, the task is done
    return 0;
}

Upvotes: 0

Manuel Barbe
Manuel Barbe

Reputation: 2164

If you can use C++11, you may have a look at the std::future class. Anyway, you need to wait for the event in the main thread somehow.

std::future<T> f = std::async(std::launch::async, <your_thread_func>);
// do something else
f.wait();
T t = f.get();

Upvotes: 1

Related Questions