Как сделать функцию асинхронной в C ++? - PullRequest
20 голосов
/ 13 апреля 2011

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

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

Ответы [ 7 ]

15 голосов
/ 13 апреля 2011

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

1998 C ++ / 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 C ++ подход (с использованием 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();
}
5 голосов
/ 13 апреля 2011

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

3 голосов
/ 13 апреля 2011

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

Во-первых, упаковка вызова функции для последующего ее выполнения.

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

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

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

Для FO у вас может быть:

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

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

std::list<Callback*> asyncQ; // Or shared_ptr or whatever.
3 голосов
/ 13 апреля 2011

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

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

1 голос
/ 13 апреля 2011

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

// 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);
0 голосов
/ 23 апреля 2019

Начиная с C ++ 11, обычный c ++ имеет концепцию потоков, но наиболее краткий способ асинхронного вызова функции - это использовать асинхронную команду C ++ 11 вместе с фьючерсами. В конечном итоге это выглядит очень похоже на то, как вы делаете то же самое в pthreads, но оно на 100% переносимо на все операционные системы и платформы:

Скажем, ваша функция имеет возвращаемое значение ... int = MyFunc (int x, int y)

#include <future>

Просто сделай:

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

подвох? Как вы знаете, когда это сделано? (Барьер.)

В конце концов, сделайте:

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

Обратите внимание, что таким образом легко провести параллель для цикла - просто создайте массив фьючерсов.

0 голосов
/ 13 апреля 2011

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

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

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

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