У меня есть рекурсивная функция в C++, и мне нужно немедленно завершить функцию, включая все вызовы, которые рекурсивно создаются через определенное время, например, 60 секунд. Я пробовал следующее, но не работает. takeTooLong - глобальная переменная, но если ее значение изменяется на 1 в одном вызове, другие вызовы продолжают видеть его как 0. ОС - Ubuntu 12.10.
main() выглядит примерно так:
int main()
{
takesTooLong = 0;
startTime = clock();
RecursiveFunction();
endTime = clock();
printf("Elapsed time: %f", CalculateElapsedTime(startTime, endTime));
return 0;
}
Моя рекурсивная функция:
void RecursiveFunction(Some Parameters)
{
if (takesTooLong == 1)
return;
endTime = clock();
differenceTime = CalculateElapsedTime(startTime, endTime);
if (differenceTime > MAX_SECONDS)
{
takesTooLong = 1;
}
if (takesTooLong == 0)
{
for (i = 0; i < n && takesTooLong == 0; i++)
{
RecursiveFunction(Some Updated Parameters);
}
}
}
Самый простой способ выйти из неизвестного числа рекурсий - это выбросить исключение. Поскольку вы делаете это не чаще одного раза в 60 секунд, это не так уж плохо. Просто сделайте его class TimeLimitExceeded: public std::runtime_error
и поймайте его в обертке верхнего уровня.
† Большинство рекурсивных функций не следует вызывать напрямую, а через нерекурсивную оболочку. Подпись рекурсивной функции обычно неудобна для вызывающих, поскольку она содержит детали реализации, которые не имеют отношения к вызывающему.
псевдокод:
typedef ??? Time;//time type
Time getCurrentTime(); //returns time. Or ticks. Anything you could use to measure time.
void recursiveFunction(Time startTime){
...//do something here
Time currentTime = getCurrentTime();
if ((currentTime - startTime) > limit)
return;
recursiveFunction(startTime);
}
void recursiveFunction(){
Time startTime = getCurrentTime();
recursiveFunction(startTime);
}
Да, вам еще нужно развернуть стек, но альтернативы все уродливые, лучше всего, вероятно, быть longjmp. Если вам требуется большее разрешение, чем секунды, или вы хотите измерить время процесса/ядра, а не время настенных часов, используйте альтернативы, такие как timer_create
или setitimer
.
void alarmHandler (int sig)
{
timedOut = 1;
}
signal(SIGALRM, alarmHandler);
alarm(60);
RecursiveFunction();
alarm(0);
if (timedOut)
{
//report something
timedOut = 0;
}
void RecursiveFunction(Some Parameters)
{
if (timedOut)
return;
//........
}