C:终止从main进入无限循环的被调用函数

时间:2018-03-30 13:45:09

标签: c infinite-loop

我们假设我在c文件中有以下主要内容

int f();
int main(){
     //terminate f() if in infinite loop
     return f();
}

然后是一个单独的c文件,它可能包含以下内容:

int f() {
    for(;;) {}
    return 0;
}

有没有办法检测函数f()是否处于无限循环中并从主函数中终止它的执行?

编辑: 我需要这个功能,因为我正在编写一个测试平台,其中调用的函数可能有一个无限循环 - 这就是我最后要检查的内容。因此,无论如何我都无法修改f()。我也在Linux环境中。

4 个答案:

答案 0 :(得分:2)

您可以在其他主题中调用f(),并在达到某个限制时主要超时f()。但是,我不认为这是实用的,你应该首先解决无限循环问题。

答案 1 :(得分:2)

在Posix系统(Linux,MacOS)上,您可以在调用该功能之前使用setitimer()安排警报。信号SIGALRM将在指定的延迟后传送到进程。确保你的程序有信号处理程序,你应该在启动计时器之前用sigaction()注册它。

当信号处理器在信号被提升后获得控制权时,如果有setjmp()longjmp()的违规循环,你可能会退出。

答案 2 :(得分:2)

不,there is no way to definitively determine if a function contains an infinite loop

但是,我们可以做一些假设来检测潜在的无限循环并在程序中优雅地退出程序(例如,我们不必按 Ctrl + C )。这种方法在JS中使用的几个测试框架中很常见。基本上,我们为一个函数设置一些任意的时间限制。如果函数没有在该时间限制内完成,我们假设它不会完成,我们抛出一个错误。

在C / C ++中,如果你使用的是Unix系统,你可以使用pthreads来实现它。在Windows中,您将使用windows.h。我只有pthreads的经验,因此我将展示一个简单的示例,说明如何使用pthread进行此操作。

#include <pthread.h>  // Load pthread
#include <signal.h>   // If f() does not exit, we will need this library to send it a signal to kill itself.
#include <stdbool.h>  // You could use an int or char.
#include <stddef.h>   // Defines NULL
#include <unistd.h>   // Defines sleep()

bool testComplete;   // Has the test completed?

/**
 * The function being tested.
 */
void f() {
    while(true);
}

/**
 * This method handles executing the test.  This is the function pthread will
 * use as its start routine.  It takes no arguments and returns no results.
 * The signature is required for pthread_create().
 */
void *runTest(void *ptr) {
    testComplete = false;

    f();

    testComplete = true;
}

int main() {
    pthread_t testThread;

    pthread_create(&testThread, NULL, runTest, NULL);  // Create and start the new thread.  It will begin executing runTest() eventually.

    sleep(5);      // Give it 5 seconds to complete (this should be adjusted or could even be made dynamic).

    if(testComplete) {
        // Test completed successfully.
        pthread_join(testThread, NULL);
    } else {
        // The test did not exit successfully within the time limit.  Kill it and you'll probably what to provide some feedback here.
        pthread_kill(testThread, SIGPIPE); // There are other signals, but this one cannot be ignored or caught.
    }
}

要编译它,您需要执行gcc your_filename.c -o output_filename -lpthread

如果您希望程序在Unix和Windows系统上运行,您可能需要考虑使用一些统一的接口来访问线程,然后将特定于操作系统的接口调整到您的接口。它会使事情变得更简单,特别是在扩展这个库时。

答案 3 :(得分:0)

如果您按照展示的方式致电f()(来自main),那么此时主要内容位于f,而不是main,因此您无法“检查来自f“的main

您可以尝试从单独的线程调用f()并检查该线程是否已在指定的时间限制内完成。但是我不确定这个的实用性。虽然我不知道你真正计划在该函数中做什么,但在某些情况下,你可能会停止执行这个函数,因为它执行了需要清理的东西。想到的一个例子是它调用malloc,但能够在你打断它的时候调用free

老实说,如果对给定函数必须完成的时间有一定的要求,只需将该检查放在函数本身中并返回false以表明它没有成功完成。