28

I want to call a function which will be asynchronous (I will give a callback when this task is done).

I want to do this in single thread.

Pharap
  • 3,826
  • 5
  • 37
  • 51
yogesh
  • 281
  • 1
  • 3
  • 5

7 Answers7

19

This can be done portably with modern C++ or even with old C++ and some boost. Both boost and C++11 include sophisticated facilities to obtain asynchronous values from threads, but if all you want is a callback, just launch a thread and call it.

1998 C++/boost approach:

#include <iostream>
#include <string>
#include <boost/thread.hpp>
void callback(const std::string& data)
{
    std::cout << "Callback called because: " << data << '\n';
}
void task(int time)
{
    boost::this_thread::sleep(boost::posix_time::seconds(time));
    callback("async task done");
}
int main()
{
    boost::thread bt(task, 1);
    std::cout << "async task launched\n";
    boost::this_thread::sleep(boost::posix_time::seconds(5));
    std::cout << "main done\n";
    bt.join();
}

2011 C++ approach (using gcc 4.5.2, which needs this #define)

#define _GLIBCXX_USE_NANOSLEEP
#include <iostream>
#include <string>
#include <thread>
void callback(const std::string& data)
{
    std::cout << "Callback called because: " << data << '\n';
}
void task(int time)
{
    std::this_thread::sleep_for(std::chrono::seconds(time));
    callback("async task done");
}
int main()
{
    std::thread bt(task, 1);
    std::cout << "async task launched\n";
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "main done\n";
    bt.join();
}
Cubbi
  • 46,567
  • 13
  • 103
  • 169
12

As of C++11, plain c++ does have a concept of threads, but the most concise way to call a function asynchronously is to use the C++11 async command along with futures. This ends up looking a lot like the way you'd do the same thing in pthreads, but it's 100% portable to all OSes and platforms:

Say your function has a return value... int = MyFunc(int x, int y)

#include <future>

Just do:

// This function is called asynchronously
std::future<int> EventualValue = std::async(std::launch::async, MyFunc, x, y); 

Catch? How do you know when it's done? (The barrier.)

Eventually, do:

int MyReturnValue = EventualValue.get(); // block until MyFunc is done

Note it's easy to do a parallel for loop this way - just create an array of futures.

user2465201
  • 471
  • 5
  • 10
7

You can't in plain C++. You'll need to use an OS-specific mechanism, and you need a point where execution is suspended in a way that allows the OS to execute the callback. E.g. for Windows, QueueUserAPC - the callback will be executed when you e.g. SleepEx or WaitForSingleObjectEx

Erik
  • 88,732
  • 13
  • 198
  • 189
  • Well, in theory, if you can figure out `std::async` and `std::future`... modern compilers certainly support those. Though sure enough _I can't_ figure them out so a 2 liner produces less than 5 compiler errors... so yeah, +1 on QueueUserAPC. – Damon Apr 13 '11 at 07:59
  • I was wondering if this can be done using Timers..I know this is possible in symbian. I am using Bada framework.They have a library for timers.But I am not sure how to exactly do that – yogesh Apr 13 '11 at 08:47
4

The long answer involves implementing your own task scheduler and wrapping your "function" up into one or more tasks. I'm not sure you want the long answer. It certainly doesn't allow you to call something, completely forget about it, and then be notified when that thing is done; however if you are feeling ambitious, it will allow you to simulate coroutines on some level without reaching outside of standard C++.

The short answer is that this isn't possible. Use multiple threads or multiple processes. I can give you more specific information if you divulge what OS/platform you're developing for.

kqnr
  • 3,596
  • 19
  • 17
  • 1
    Using a runloop it is possible to do asynchronous stuff in a single thread (but you probably need a complete framework with support for that). Apple's Objective-C/Cocoa framework is a nice example of how it can be done. – DarkDust Apr 13 '11 at 06:54
  • Well, I wouldn't call Cocoa a "nice" example of anything (IMHO!;)), but yes - that is a good example of a single-threaded task scheduler. – kqnr Apr 13 '11 at 06:58
  • I am using Bada, but I am not sure if everyone is familiar with it..thats why I was asking a generic approach – yogesh Apr 13 '11 at 08:49
4

There are two bits to doing this.

Firstly, packing up the function call so that it can be executed later.

Secondly, scheduling it.

It is the scheduling which depends on other aspects of the implementation. If you know "when this task is done", then that's all you need - to go back and retrieve the "function call" and call it. So I am not sure this is necessarily a big problem.

The first part is then really about function objects, or even function pointers. The latter are the traditional callback mechanism from C.

For a FO, you might have:

class Callback
{
public:
  virtual void callMe() = 0;
};

You derive from this and implement that as you see fit for your specific problem. The asyncronous event queue is then nothing more than a list<> of callbacks:

std::list<Callback*> asyncQ; // Or shared_ptr or whatever.
drewish
  • 9,042
  • 9
  • 38
  • 51
Keith
  • 6,756
  • 19
  • 23
  • I will not know how much time my function would take, thats why I need it to be async – yogesh Apr 13 '11 at 08:58
  • @yogesh: In that case you should do it in a separate thread. If you're using a single thread and have a function that blocks for a longer time (> 0.1s) you will see it in your UI as it won't respond immediately and/or animations become choppy. – DarkDust Apr 13 '11 at 09:36
  • @yogesh: As DarkDust stated, you are really after threading. Probably you should just dive in and try it. _If_ your work task can be broken into a series of smaller (i.e. < 0.1s) tasks which are queued individually, you can use a queue like the above and processing it during GUI idle time. – Keith Apr 14 '11 at 00:18
2

I'm not sure I understand what you want, but if it's how to make use of a callback: It works by defining a function pointer, like this (untested):

// Define callback signature.
typedef void (*DoneCallback) (int reason, char *explanation);

// A method that takes a callback as argument.
void doSomeWorkWithCallback(DoneCallback done)
{
    ...
    if (done) {
       done(1, "Finished");
    }   
}

//////

// A callback
void myCallback(int reason, char *explanation)
{
    printf("Callback called with reason %d: %s", reason, explanation);
}

/////

// Put them together
doSomeWortkWithCallback(myCallback);
DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • 2
    This would be awesome if it fulfilled the asynchronous requirement - meaning `doSomeWorkWithCallback(myCallback)` would return immediately while continuing to do work in parallel with the caller, and `myCallback` would be called at some later time when said work was finished. Alas... – kqnr Apr 13 '11 at 06:54
  • Yes this is what I exactly wanted – yogesh Apr 13 '11 at 08:45
0

As others have said, you technically can't in plain C++.

However, you can create a manager that takes your task and does time-slicing or time scheduling; with each function call, the manager uses a timer to measure the amount of time the process took; if the process took less time than scheduled, and it thinks it can finish another call and use up the remaining time without going over, it can call it again; if the function does go over the alloted time, it means the function has less time next update to run. So, this will involve creating a somewhat complex system to handle it for you.

Or, if you have a specific platform in mind, you could use threading, or create another process to handle the work.

leetNightshade
  • 2,673
  • 2
  • 36
  • 47