Как сделать функцию асинхронной в С++?

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

Я хочу сделать это в одном потоке.

Ответы

Ответ 1

Это можно сделать портативно с помощью современного С++ или даже со старыми С++ и некоторыми boost. Оба boost и С++ 11 включают сложные средства для получения асинхронных значений из потоков, но если все, что вы хотите, является обратным вызовом, просто запустите поток и вызовите его.

1998 С++/boost подход:

#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 С++-подход (с использованием gcc 4.5.2, которому требуется это #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();
}

Ответ 2

Вы не можете использовать простой С++. Вам нужно будет использовать механизм, специфичный для ОС, и вам потребуется точка, в которой выполнение приостанавливается таким образом, чтобы ОС могла выполнить обратный вызов. Например. для Windows, QueueUserAPC - обратный вызов будет выполнен, когда вы, например. SleepEx или WaitForSingleObjectEx

Ответ 3

Для этого есть два бита.

Сначала упакуйте вызов функции, чтобы он мог быть выполнен позже.

Во-вторых, планирование его.

Это планирование, которое зависит от других аспектов реализации. Если вы знаете, "когда эта задача выполнена", то все, что вам нужно - вернуться и получить "вызов функции" и вызвать его. Поэтому я не уверен, что это обязательно большая проблема.

Первая часть - это действительно о объектах функций или даже указателях функций. Последние являются традиционным механизмом обратного вызова из C.

Для FO вы можете:

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

Вы извлекаете из этого и реализуете это, как вы сочтете нужным для вашей конкретной проблемы. Асинхронная очередь событий - это не более чем list<> обратных вызовов:

std::list<Callback*> asyncQ; // Or shared_ptr or whatever.

Ответ 4

Длительный ответ включает в себя реализацию вашего собственного планировщика задач и перенос вашей "функции" в одну или несколько задач. Я не уверен, что тебе нужен длинный ответ. Это, безусловно, не позволяет вам что-то называть, полностью забыть об этом, а затем уведомляться, когда это делается; однако, если вы чувствуете амбициозность, это позволит вам симулировать сопрограммы на каком-то уровне, не выходя за пределы стандартного С++.

Короткий ответ заключается в том, что это невозможно. Используйте несколько потоков или несколько процессов. Я могу дать вам более конкретную информацию, если вы раскрываете, какую ОС/платформу вы разрабатываете.

Ответ 5

Я не уверен, что понимаю, что вы хотите, но если это поможет сделать обратный вызов: он работает, определяя указатель на функцию, как это (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);

Ответ 6

Как говорили другие, вы технически не можете на простом С++.

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

Или, если у вас есть определенная платформа, вы можете использовать потоки или создать другой процесс для обработки работы.