Асинхронный вызов функции для C ++ - PullRequest
6 голосов
/ 02 августа 2010

Мне нужен совет, как реализовать асинхронные вызовы функций в C / C ++ (или имена фреймворков / API-вызовов для Windows и / или Linux)

Вариант использования следующий: родительский поток вызывает функцию. Функция создает дочерний поток и возвращает его, поэтому вызов неблокируемый, и родительский поток может продолжать выполнять некоторую работу.

Например, pthread_join для получения результата не подходит, поэтому результат должен храниться где-то в куче, а родитель должен быть уведомлен об этом. Мне нужно что-то вроде функции обратного вызова в родительском потоке, которая будет выполняться после того, как дочерний поток будет готов к работе.

Это удивительно, но я не могу найти ни одного примера в Google.

Спасибо за помощь

Ответы [ 8 ]

8 голосов
/ 04 августа 2010

C ++ 0x обеспечивает std::async для этого.Вот существующая реализация , обсуждение и Википедия .

7 голосов
/ 12 августа 2010

Вместо того, чтобы использовать разные фреймворки и отмечая, что вы упомянули pthread_join() в своем вопросе, вы все равно можете достичь желаемого эффекта с помощью POSIX C. Для этого вы можете использовать сигналы для подтверждения потока выполнения параллельной задачи , В этом методе вы устанавливаете обработчик сигнала для определяемого пользователем сигнала (например, SIGUSR1), создаете набор рабочих потоков с различными задачами и позволяете им сигнализировать родителю, когда они завершены.

Следующая программа иллюстрирует попытку. В этом примере я использую SIGUSR1, чтобы сообщить родительскому потоку о завершении некоторой обработки. Родительский поток остается занятым, выполняя некоторые операции ввода-вывода, пока его не прервет дочерний поток. Обратите внимание, что для ясности, никакой код обработки ошибок не был помещен.

#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;
}

В примере используется реализация сигналов LinuxThreads, которая сильно отличается от того, что определяет POSIX. Если вы обеспокоены переносимостью или совместимостью, приведенное выше решение следует дополнительно пересмотреть.

4 голосов
/ 02 августа 2010

Предлагаю вам проверить http://www.threadingbuildingblocks.org/.

Класс заданий (http://cache -www.intel.com / cd / 00/00/30/11 / 301114_301114.pdf # page =95 ) может быть отправной точкой.

3 голосов
/ 02 августа 2010

Boost.Thread

Я верю, что это хорошо работает. Раскрутите вызов функции как новый поток и просто не беспокойтесь о присоединении к нему. Я все равно позабочусь об этом, когда все закончится.

Вы можете настроить его так, чтобы дочерний элемент посылал сигнал родителю, когда он заканчивает, используя Boost.Signals . Этот сигнал будет связан с функцией обратного вызова родителя.

1 голос
/ 02 августа 2010

Используйте boost :: thread в качестве стандартного кроссплатформенного решения. Если вам нужно что-то более сложное, есть блоки Intel Thread Building Blocks.

0 голосов
/ 12 августа 2010

В вашем ответе Starkey я вижу, что основной поток - это поток пользовательского интерфейса.

Я использовал несколько различных наборов инструментов с графическим интерфейсом, и все они позволяют вам публиковать сообщения из другой темы.Поэтому, если рабочий поток отправит сообщение с графическим интерфейсом после его завершения, обработчик будет работать в главном потоке.

В Windows используйте PostMessage.

В Linux используйте XtAppAddSignal и XtNoticeSignal

0 голосов
/ 02 августа 2010

Используйте каркас Qt и Thread классы или платформу Qt Concurrency .

Подключитесь к сигналу QThread :: finish () или QFutureWatcher :: finish (), чтобы получить уведомление о завершении работы.

0 голосов
/ 02 августа 2010

Вам нужно будет настроить какую-то инфраструктуру, чтобы уведомить вызывающего абонента о том, что работа выполнена.Это может быть сделано с типом шаблона Observer.Также может использоваться инфраструктура типов сообщений.

Реальный вопрос в том, что будет делать ваш родитель, пока он ждет.Вы хотите, чтобы это опросило результаты?Или получить уведомление?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...