тайм-аут в std :: async

Есть ли способ реализовать тайм-аут в методе std :: async, поэтому я хочу, чтобы этот вызов тайм-аут и завершился, если поток не завершен в течение указанного периода времени. Как я могу реализовать эту функциональность.

3

Решение

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

Я хотел бы сделать что-то вроде этого:

#include <chrono>

template <typename Clock = std::chrono::steady_clock>
class timeout
{
public:
typedef Clock clock_type;
typedef typename clock_type::time_point time_point;
typedef typename clock_type::duration duration;

explicit timeout(duration maxDuration) :
mStartTime(clock_type::now()),
mMaxDuration(maxDuration)
{}

time_point start_time() const
{
return mStartTime;
}

duration max_duration() const
{
return mMaxDuration;
}

bool is_expired() const
{
const auto endTime = clock_type::now();

return (endTime - start_time()) > max_duration();
}

static timeout infinity()
{
return timeout(duration::max());
}

private:
time_point mStartTime;
duration mMaxDuration;
};

Эта простая утилита отслеживает время начала и максимальную продолжительность (и предоставляет способ указания бесконечности) и позволяет пользователю запрашивать простые факты, наиболее важно, произошел ли тайм-аут или нет.

Тест ниже; Вы можете добавить ложную задержку, определив / не определив FAKE_DELAY:

#include <iostream>
#include <future>

#define FAKE_DELAY

void fake_delay()
{
#ifdef FAKE_DELAY
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
#endif
}

void short_running_function(timeout<> timelimit)
{
fake_delay();

if (timelimit.is_expired())
std::cout << "short running thread ran out of time" << std::endl;
else
std::cout << "short running function finished" << std::endl;
}

void long_running_function(timeout<> timelimit)
{
for (unsigned i = 0; i < 10; ++i) {
if (timelimit.is_expired())
{
std::cout << "long running thread ran out of time" << std::endl;
return;
}

std::cout << "long running thread doing work" << std::endl;
fake_delay();
}

std::cout << "long running function finished" << std::endl;
}

int main()
{
std::async(short_running_function,
timeout<>(std::chrono::milliseconds(500))).wait();

std::async(short_running_function,
timeout<>(std::chrono::milliseconds(5000))).wait();

std::async(long_running_function,
timeout<>(std::chrono::milliseconds(500))).wait();

std::async(long_running_function,
timeout<>(std::chrono::milliseconds(5000))).wait();

std::async(long_running_function,
timeout<>::infinity()).wait();
}

Один возможный выход с FAKE_DELAY от:

функция короткого хода закончена
функция короткого хода закончена
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долгосрочная функция закончена
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долгосрочная функция закончена
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долгосрочная функция закончена

Один возможный выход с FAKE_DELAY на:

короткая нить закончилась время
функция короткого хода закончена
долго работающий поток делает работу
долго работающий поток исчерпал время
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток исчерпал время
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долго работающий поток делает работу
долгосрочная функция закончена

5

Другие решения

Стандарт не предусматривает какого-либо способа не-кооперативного уничтожения потока. Отсутствие функции автоматического тайм-аута является еще одним примером этого.

Вместо этого вы должны реализовать код, который вы передаете std::async справиться с этим совместно. Один шаблон для совместного уничтожения потока состоит в том, чтобы передать функции объект, который предоставляет метод, чтобы проверить, должна ли асинхронная функция продолжаться, и если нет, она выдает исключение.

struct Time_out {
std::chrono::steady_clock start = std::chrono::steady_clock::now();
std::chrono::milliseconds timeout;
Time_out(std::chrono::milliseconds t) : timeout(t) {}

void check() {
if (start + timeout < std::chrono::steady_clock::now())
throw timeout_exception();
}
};

std::future<void> f = std::async([](Time_out t) {
while(more work) {
// do work
t.check();
}
}, Time_out(std::chrono::seconds(2));

f.get();
5

По вопросам рекламы [email protected]