6

I need a hint how to implement asynchronous function calls in C/C++ ( or names of frameworks/API calls for windows and/or linux )

The use case is following: A parent thread calls a function. The function creates a child thread and returning, so call is non-blocking and parent thread can continue to do some job.

For example pthread_join to get result is not suitable, so result must be stored somewhare in heap and parent must be notified about. What I want is something like callback function in parent thread, that would be executed after child thread is ready with job.

This is surprising, but I can not find a single example in google.

Thanks for help

iddqd
  • 193
  • 1
  • 1
  • 5
  • Just so we get a reference what language/framework are you modelling your question on. You seem to have something very specific in mind. If you could provide a reference somebody may know of an equivalent framework for C++. But as answered below the basic building block would be boost::threads though this is very low level compared to what you want. – Martin York Aug 02 '10 at 17:04
  • 12
    Which one, C or C++?? Make up your mind people!! – Edward Strange Aug 02 '10 at 17:07

8 Answers8

8

C++0x provides std::async for this. Here's an existing implementation, a discussion, and Wikipedia.

Victor Lamoine
  • 389
  • 1
  • 2
  • 21
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
7

Rather than using different frameworks, and noting that you've mentioned pthread_join() in your question, you can still achieve the desired effect with POSIX C. For that, you can use signals to acknowledge a thread of a parallel task completion. In this method, you install a signal handler for a user-defined signal (SIGUSR1, for example), create a set of working threads with different tasks and let them signalize the parent when they are complete.

The following program illustrates the attempt. In the example, I use SIGUSR1 to inform the parent thread of the completion of some processing. The parent thread is kept busy doing some I/O until interrupted by the child thread. Note that, for clarity, no error-handling code of any sort has been put.

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* Variable to hold the value of some calculation. */
int value = 0;

/* Variable used by the parent thread to inform itself of task completion. */
volatile sig_atomic_t value_received = 0;

/* Signal handler to handle the SIGUSR1 signal (the signal used to acknowledge the parent of task completion). */
void handler(int signum) {
    value_received = 1;
}

/* Working thread routine. First parameter is a pthread_t (cast to void*) identifying the parent. */
void *thread(void *parent) {
    /* Do something lengthy here, such as a long calculation. */
    value = 1;
    sleep(5); /* Simulate lengthy operation. */

    /* After processing, inform the parent thread that we have ended. */
    pthread_kill((pthread_t)parent, SIGUSR1);
    return NULL;
}

int main(void) {
    struct sigaction action;
    pthread_t child;

    /* Install signal handler to receive the child thread notification. */
    action.sa_handler = handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGUSR1, &action, NULL);

    /* Create child thread that will perform some task. */
    pthread_create(&child, NULL, thread, (void*)pthread_self());

    /* Detach thread from execution. No need to join the thread later. */
    pthread_detach(child);

    /* Do some other processing while the ongoing task is running in parallel. */
    while (!value_received) {
        char buffer[0x100];

        /* Echo some input until something happens. */
        if (!fgets(buffer, sizeof buffer, stdin))
            break;
        printf("You typed: %s", buffer);
    }

    /* Something happened (signal received or EOF in stdin). In the latter, just sleep a little while. */
    if (feof(stdin))
        while (!value_received)
            sleep(1);

    /* At this point, child thread has already ended the execution. */
    printf("Value received: %i\n", value);
    return EXIT_SUCCESS;
}

The example uses the LinuxThreads implementation of signals, which is quite different from what POSIX defines. If you are concerned with portability or compliance, the above solution should be further revised.

alecov
  • 4,882
  • 2
  • 29
  • 55
  • 1
    This is standard, and it is C, but it is not standard C. (sigaction, pthreads, etc are part of the POSIX or SUS standards, not the ANSI C standard) – Ben Voigt Aug 12 '10 at 03:26
  • @BenVoigt You are correct. However, I would tend to think most C and C++ programmers may be inclined to use Linux and by default most major Linux Distros ship with POSIX. Please correct me if I am wrong. – enthusiasticgeek Jun 04 '13 at 16:50
  • @enthusiasticgeek: You are wrong. Linux has a pretty small market share of C and C++. For C especially, the majority of platforms are too small to run Linux. And for desktop applications, the majority of programmers have a desire that it also work on Windows, even if they develop using Linux. But even in developer communities, Windows has more market share than Linux (the difference of course being much smaller than among users). – Ben Voigt Jun 04 '13 at 17:47
  • But really, even if your comment were true, there's still no advantage to incorrectly writing "standard C". – Ben Voigt Jun 04 '13 at 17:48
  • @BenVoigt I see. Maybe because I work exclusively with C++ on Linux (embedded and servers) and mostly everyone in my office. But again our front-end is all Windows and Java. I also didn't catch "standard C" (emphasis on - standard) comment he wrote earlier. – enthusiasticgeek Jun 04 '13 at 18:41
4

I suggest you check out http://www.threadingbuildingblocks.org/.

The Task class (http://cache-www.intel.com/cd/00/00/30/11/301114_301114.pdf#page=95) may be a starting point.

Damyan
  • 1,563
  • 9
  • 15
3

Boost.Thread

I believe this does the job well. Spin up the function call as a new thread and just don't bother joining it. It'll take care of that when it finishes anyway I believe.

You could set it up so the child sends a signal to the parent when it finishes using Boost.Signals. This signal would be linked to the parent's callback function.

Jonathan Sternberg
  • 6,421
  • 7
  • 39
  • 58
  • I have already looked at boost-signals and it seems not to be what I want. I haven't tryed yet, but I it seems that a "slot"-function would be executed in context of current ( in my case child ) thread. Please correct me if I am wrong – iddqd Aug 02 '10 at 16:47
  • Misunderstood the question. Boost.Thread is really what you want. Editing my answer. – Jonathan Sternberg Aug 02 '10 at 16:59
1

Use boost::thread as the standard cross-platform solution. If you need something more involved, there's Intel's Thread Building Blocks.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • I have looked docs and it seems that boost doesn't provide such implementation. It is not possible to provide a "callback" function for thread or future object. There is set_wait_callback but it is invoked only if a future object is *not* ready – iddqd Aug 02 '10 at 18:27
0

You'll have to set up some kind of infrastructure to notify the caller that the work is done. This could be done with an Observer pattern type. A message type infrastructure can be used as well.

The real question is what is your parent going to do while it waits. Do you want it to poll for results? Or get notified?

Starkey
  • 9,673
  • 6
  • 31
  • 51
  • a parent thread can for example handle message loop for GUI. I want to get notified - this is always possible to give a function a pointer to buffer where result would be stored and since threads are in the same process the result can be easy read in "callback" function – iddqd Aug 02 '10 at 16:50
0

Use Qt framework and Thread classes or the Qt Concurrency framework.

Connect to QThread::finished() or QFutureWatcher::finished() signal to be notified when the work is done.

TimW
  • 8,351
  • 1
  • 29
  • 33
0

I see in your reply to Starkey that the main thread is a UI thread.

I've used several different GUI toolkits and all of them allow you to post a message from a different thread. So have the worker thread post a GUI message when it is complete, the handler will then run in the main thread.

In Windows, use PostMessage.

In Linux, use XtAppAddSignal and XtNoticeSignal

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720