Code Monkey home page Code Monkey logo

Comments (4)

MonaTheMonad avatar MonaTheMonad commented on June 1, 2024 1

Without when_any for the time being, what would be a good way check whether a task has completed either within a certain timeout value or by a certain time?

from cppcoro.

lewissbaker avatar lewissbaker commented on June 1, 2024

A somewhat cumbersome way of implementing the when_any() pattern such that the first operation to complete is a "winner" and the others are "losers" and should be cancelled:

task<> alternative1(cancellation_token ct);
task<> alternative2(cancellation_token ct);

task<> cancel_on_success(task<> t, cancellation_source cs)
{
  co_await t;
  cs.request_cancellation();
}

task<> do_1_or_2(cancellation_token ct)
{
  cancellation_source source;
  cancellation_registration cancellationForwarder{ ct, [&source] { source.request_cancellation(); } };
  co_await when_all(
    cancel_on_success(alternative1(source.token()), source),
    cancel_on_success(alternative2(source.token()), source));
}

This will cancel both sub-tasks if the cancellation_token passed in has cancellation requested.
When either sub-task completes successfully (ie. without throwing an exception) then it will request cancellation of the other task.

from cppcoro.

lewissbaker avatar lewissbaker commented on June 1, 2024

The other main use-case of when_any() is to act as an event loop, allowing code to handle completion of a number of concurrently executing tasks serially in the order they complete in.

eg. Something like this (not thoroughly thought out)

task<std::string> get_record(int id);

task<> example()
{
  std::vector<task<std::string>> tasks;
  for (int i = 0; i < 100; ++i) tasks.push_back(get_record(i));

  while (!tasks.empty())
  {
    std::size_t readyIndex = co_await when_any(tasks);
    std::cout << co_await tasks[readyIndex] << std::endl;
    tasks.erase(tasks.begin() + readyIndex);
  }
}

However, I feel that something like this could be handled just as well using (and possibly more efficiently) using when_all to execute them concurrently and async_mutex to serialise processing of each individual event.
eg.

task<std::string> get_record(int id);

task<> example()
{
  async_mutex mutex;

  auto handleRecord = [&](int id) -> task<>
  {
    auto& result = co_await get_record(id);
    {
      auto lock = co_await mutex.scoped_lock_async();
      std::cout << result << std::endl;
    }
  };

  std::vector<task<>> tasks;
  for (int i = 0; i < 100; ++i) tasks.push_back(handleRecord(i));
  co_await when_all(std::move(tasks));
}

from cppcoro.

lewissbaker avatar lewissbaker commented on June 1, 2024

If you just want to check whether a task completed within a certain time then you can just query the time both before and after the task completes and check the total time taken.

If you want to cancel the operation after a certain timeout has elapsed then you can use when_all() to execute the task concurrently with a schedule_after(timeout) operation and then use a cancellation_token to cancel the task after the timeout has elapsed.

cppcoro::task<int> foo(cppcoro::cancellation_token ct);

cppcoro::task<int> foo_with_timeout(
  cppcoro::io_service& ioSvc,
  std::chrono::milliseconds timeout)
{
  cppcoro::cancellation_source src;
  auto [result, unused] = co_await cppcoro::when_all(
    [&]() -> cppcoro::task<int> {
      auto cancelOnExit = cppcoro::on_scope_exit([&] { src.request_cancellation(); });
      co_return co_await foo(src.token());
    }(),
    [&]() -> cppcoro::task<void> {
      auto cancelOnExit = cppcoro::on_scope_exit([&] { src.request_cancellation(); });
      co_await ioSvc.schedule_after(timeout);
    }());
  co_return result;
}

This will then need the operation to wait for the timer to be cancelled before it can return a result, however. You may be able to use the async_scope class to spawn the timer task to be waited for at a higher-level and avoid the extra latency.

from cppcoro.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.