2016-10-31 1 views
1

Допустим, у нас есть блок кода, мы просто не можем его изменить, но мы хотим его сломать, выйти из этого фрагмента кода, когда он работает слишком долго (x miliseconds)C++ 11 выполнить блок в том же потоке, но с таймаутом

Псевдокод

Throw exception after (500ms) { 
    auto result = Do some risky job, for example test string by regex with catastrophic backtracking risk. 
} 
catch (Exception e) { 
    //... 
} 

Каждая вещь должна быть по-прежнему в том же потоке.

Возможно ли с помощью C++ 11 или с некоторым другим стандартом?

+0

Имеет ли значение ОС - например, SIG_ALARM на linux, безусловно, разрешит это # ​​ – UKMonkey

+0

@UKMonkey: Это для add.js node под FreeBSD. Но я думаю, что каждая информация поможет. – ElSajko

+2

Самый простой способ - фактически запустить рискованный бизнес в отдельном потоке. Затем вы ожидаете результат в 'std :: future', используя http://en.cppreference.com/w/cpp/thread/future/wait_for. – StoryTeller

ответ

2

FreeBSD (а также все другие типы Linux) имеют «SigAlarm»: Reference here

Это позволит вам настроить таймер; и когда событие запускается, ваш текущий код прерывается, а обработчик сигнала вызывается, настроенный по вашему предыдущему звонку на signal

Это позволит вам установить флаг, с которым может справиться ваша очень опасная нить; а затем бросить, если потребуется.

Это не позволит вам создавать исключения прямо так, как вы хотите, но это позволит вам поддерживать однопоточное приложение.

+0

На самом деле вы даже можете бросить при использовании setjmp/longjmp с обработчиком сигнала. Я использовал это один раз, чтобы перевести сигналы на исключения C++. – axalis

+0

Пример longjump [здесь] (https://www.gnu.org/software/libc/manual/html_node/Longjmp-in-Handler.html#Longjmp-in-Handler) – UKMonkey

+0

setjmp/longjmp, когда есть объекты RAII в автоматическом хранении это не очень хорошая идея. – Yakk

2

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

Вы можете встроить ASL, язык сценариев или отдельный процесс. Все 3 могут быть спроектированы так, чтобы их прерывали (процессы, например, можно убить).

Boost имеет прерывистые потоки. Как это работает, так это то, что у него есть крючки в примитивах синхронизации синхронизации (мьютексы и т. Д.), Поэтому, когда вы взаимодействуете с ними, он проверяет, был ли ваш поток остановлен. Если это так, он затем выдает исключение.

Простое, частичное решение является

std::vector<std::future<R()>> futures; 
futures.push_back(std::async(std::launch::async, []()->R{ /* code */)); 
using std::chrono::literals; 
if (futures.back().wait_for(500ms)==std::future_status::ready) { 
    auto r = futures.back().get(); 
    futures.pop_back(); 
    clear_ready_futures(futures); // wait for 0ms and if so, discard and destroy 
    return r; 
} 
// failed case 

здесь наши futures магазинов в несуществующих фьючерсах (нити, по сути). clear_ready_futures очищает все старые, которые закончились.

Задачи, которые были запущены, по-прежнему выполняются до завершения, краду процессора, но вызывающий код не должен ждать их.

+0

Если это случается очень часто, следует ли рассматривать один поток и просто отправлять ему задания? вместо того, чтобы создавать новый каждый раз, когда у меня есть работа, которая должна быть выполнена? – ElSajko

+0

И еще один вопрос. Может ли это значительно снизить уровень кода? код, который обычно не будет иметь тайм-аута. – ElSajko

+0

Уверен, что очередь заданий и пул потоков легко писать (многие из них можно найти на SO). Значительное зависит от того, что значимо: ns, ms, s? Действительно, измерить. – Yakk

Смежные вопросы