Skip to content

egorshamshura/cpp-executor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Executors framework

Executors и Tasks

  • Task - это какой-то кусок вычислений. Сам код вычисления находится в методе Run() и определяется пользователем.
  • Executor - это набор потоков, которые могут выполнять Task-и.
  • Executor должен запускать потоки в конструкторе, во время работы новых потоков создаваться не должно.
  • Чтобы начать выполнять Task, пользователь должен отправить его в Executor с помощью метода Submit().
  • После этого, пользователь может дождаться пока Task завершится, позвав метод Task::Wait.
class MyPrimeSplittingTask : public Task {
    Params params_;
public:
    MyPrimeSplittingTask(Params params) : params_{params} {
    }
    bool is_prime = false;
    void Run() override {
        is_prime = CheckIsPrime(params_);
    }
}

bool DoComputation(std::shared_ptr<Executor> pool, Params params) {
    auto my_task = std::make_shared<MyPrimeSplittingTask>(params);
    pool->Submit(my_task);
    my_task->Wait();
    return my_task->is_prime;
}
  • Task может завершиться успешно (IsCompleted), с ошибкой (IsFailed) и быть отменён (IsCanceled). После того, как с ним произошло одно из этих событий - он считается выполненным (IsFinished).

  • Пользователь может в любой момент отменить Task с помощью метода Cancel(). В этом случае, если выполнение Task-и еще не началось, то оно и не должно начаться.

  • Task может иметь зависимости. Например в задаче reduce сначала должны были выполниться reduce-ы по кускам вектора, а потом один финальный reduce по промежуточным значениям. Пользователь может сказать, что один Task должен выполняться только после того как выполнился какой-то другой Task, позвав метод Task::AddDependency.

  • Task может иметь триггеры (Task::AddTrigger). В таком случае он должен начать выполнение после того как хотя бы один триггер завершился.

  • Task может иметь один триггер по времени (Task::SetTimeTrigger). В этом случае он должен начать выполнение если наступило время deadline.

  • В общем случае, Executor::Submit не должен начинать выполнение сразу, а дожидаться условия:

    • Или есть зависомости и все они выполнились
    • Или один из триггеров выполнился
    • Или выставлен deadline, и наступило время deadline. Если у таска нет зависимостей, нет триггеров и не выставлен deadline, то его можно выполнять сразу же. Пока Submit на таск не вызван, выполнять его нельзя.
  • Executor предоставляет API для того, чтобы остановить выполнение.

    • Executor::StartShutdown - начинает процесс остановки. Task-и, которые были посланы после StartShutdown, должны сразу переходить в состояние Canceled. Функция может быть вызвана несколько раз.
    • Executor::WaitShutdown - блокируется, пока Executor не остановится. Функция может быть вызвана несколько раз.
    • Executor::~Executor - неявно делает shutdown и дожидается завершения потоков.

Futures

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

  • Future - это Task, у которого есть результат (какое-то значение).

  • Интерфейсы комбинаторов определены в классе Executor:

    • Invoke(fn) - выполнить fn внутри Executor-а, результат вернуть через Future.
    • Then(input, fn) - выполнить fn, после того как закончится input. Возвращает Future на результат fn не дожидаясь выполнения input.
    • WhenAll(vector<FuturePtr<T>>) -> FuturePtr<vector<T>> - собирает результат нескольких Future в один.
    • WhenFirst(vector<FuturePtr<T>>) -> FuturePtr<T> - возвращает результат, который появится первым.
    • WhenAllBeforeDeadline(vector<FuturePtr<T>>, deadline) -> FuturePtr<vector<T>> - возвращает все результаты, которые успели появиться до deadline.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published