2

I have an asynchronous process running (using std::async) which I want to measure the execution time and kill it if its taking too long. This process also returns a value after its execution, I would like to assign some default value as the result if it takes too long to compute. Any help/suggestions would be much appreciated!

#include <thread>
#include <future>

int compute(int val)
{
    int result;

    // do large computations

    return result;
}
void main()
{
    auto compute_thread = std::async(compute, 100);

    // TODO: wait for result only for x milliseconds else assign some default value
    int result = compute_thread.get();

    // resume sequential code.
    int final = result * 2;
}
Rakshith G B
  • 816
  • 2
  • 8
  • 24
  • Make the async task monitor the time it uses and cleanup and exit returning the default value if it exceeds the time limit. There is no clean way to kill a thread. – Richard Critten Sep 05 '19 at 09:10
  • see https://stackoverflow.com/questions/12086622/is-there-a-way-to-cancel-detach-a-future-in-c11 – Alan Birtles Sep 05 '19 at 09:11
  • What if you put that waiting logic inside of the `compute()` function. It will return one value when the execution is fast and another value (early return) otherwise. – vahancho Sep 05 '19 at 09:19
  • @AlanBirtles is it possible to monitor the atomic variable in main() instead of the thread itself? Where the thread sets the state of the atomic variable. Since checking for the atomic state in high frequency at the thread level will complicate the architecture. – Rakshith G B Sep 05 '19 at 09:20
  • 2
    *want to ... kill it* You cannot kill a thread. Sorry. If you want it to terminate, you have to make it want to terminate. – n. m. could be an AI Sep 05 '19 at 10:05
  • @vahancho could you share a small example on how to do that? – Rakshith G B Sep 05 '19 at 11:54
  • @n.m. yes sure, but is there any intuitive way of getting that done? All solutions seems to point out to frequently checking the time in the compute loop and safely return. I'm not really liking the idea of doing it inside the compute loop. – Rakshith G B Sep 08 '19 at 19:01
  • If you want a killable computation, make it a separate process rather than a thread. Otherwise, you will check the termination condition inside the compute loop, and you will *like* it. – n. m. could be an AI Sep 08 '19 at 19:29
  • @n.m. yeah I don't think I can use it as process in my case. This was just a basic example to understand if such a thing was even possible. Thanks for your inputs – Rakshith G B Sep 08 '19 at 20:18

2 Answers2

0

Here is how my idea looks like (see inline code comments):

// Performs computations and exits when computation takes
// longer than maxTime. If the execution is timed out
// function returns valueIfTooLong.
// If the computation complete the function returns 0.
static int compute(int maxTime /*ms*/, int valueIfTooLong)
{
  auto start = std::chrono::steady_clock::now();
  for (short i = 0; i < std::numeric_limits<short>::max(); ++i)
  {
    auto now = std::chrono::steady_clock::now();
    if (std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count() > maxTime)
    {
      return valueIfTooLong;
    }
  }

  return 0;
}

Usage of the function:

int main()
{
  const auto valueIfTooLong = 111;
  const auto waitingTime = 10; // ms.
  auto compute_thread = std::async(std::launch::async, compute, waitingTime, valueIfTooLong);

  // Wait for result only for waitingTime milliseconds else assign valueIfTooLong
  int result = compute_thread.get();
  if (result == valueIfTooLong)
  {
    std::cout << "The calculation was longer than "
              << waitingTime << "ms. and has been terminated" << '\n';
  }
  else
  {
    std::cout << "The calculation is done" << '\n';
  }

  return 0;
}
vahancho
  • 20,808
  • 3
  • 47
  • 55
-2

You can use

std::future<int> compute_thread;
void main()
{
    auto timeToWait = std::chrono::system_clock::now() + std::chrono::minutes(1); // wait for a minute
    compute_thread = std::async(compute, 100);

    // TODO: wait for result only for x milliseconds else assign some default value
    std::future_status status = compute_thread.wait_until(timeToWait);

    if(status == std::future_status::ready)
        int final = compute_thread.get() * 2;
    else
        // you need another value based on what you're doing
}

Note: if your async is a long computation you may have for example another function that calculates the same thing but less accurate... In this case there's not a kill of the sync task. You only wait for the completion (if in time) and you kepp doing your job if the result is not ready... It's a way to not being blocked on a compute_thread.wait()

Note 2: std::future<int> compute_thread is declared as global, because if you do this in a function (not in main) you have to make sure that compute_thread's life is longer than the function life.

Sordinho
  • 49
  • 5
  • 1
    This doesn't stop `compute` from running, and it uses global state. – Caleth Sep 05 '19 at 10:25
  • @Caleth it's written in the notes, read them... This is a way to not stop in waiting the result... I think the wait for the result is the problem – Sordinho Sep 05 '19 at 10:38