如何在C中设置函数的超时?

时间:2011-10-12 10:21:08

标签: c

我要求我必须给xx ms执行一个函数。在xx ms之后我必须中止该功能。请帮我讲解如何在C中实现它。

5 个答案:

答案 0 :(得分:13)

我认为最好的方法是使用pthreads。启动可能需要在其自己的线程中取消的计算,并在主线程中使用pthread_cond_timedwait:

#include <time.h>
#include <pthread.h>
#include <stdio.h>
/* for ETIMEDOUT */
#include <errno.h>
#include <string.h>

pthread_mutex_t calculating = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t done = PTHREAD_COND_INITIALIZER;

void *expensive_call(void *data)
{
        int oldtype;

        /* allow the thread to be killed at any time */
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);

        /* ... calculations and expensive io here, for example:
         * infinitely loop
         */
        for (;;) {}

        /* wake up the caller if we've completed in time */
        pthread_cond_signal(&done);
        return NULL;
}

/* note: this is not thread safe as it uses a global condition/mutex */
int do_or_timeout(struct timespec *max_wait)
{
        struct timespec abs_time;
        pthread_t tid;
        int err;

        pthread_mutex_lock(&calculating);

        /* pthread cond_timedwait expects an absolute time to wait until */
        clock_gettime(CLOCK_REALTIME, &abs_time);
        abs_time.tv_sec += max_wait->tv_sec;
        abs_time.tv_nsec += max_wait->tv_nsec;

        pthread_create(&tid, NULL, expensive_call, NULL);

        /* pthread_cond_timedwait can return spuriously: this should
         * be in a loop for production code
         */
        err = pthread_cond_timedwait(&done, &calculating, &abs_time);

        if (err == ETIMEDOUT)
                fprintf(stderr, "%s: calculation timed out\n", __func__);

        if (!err)
                pthread_mutex_unlock(&calculating);

        return err;
}

int main()
{
        struct timespec max_wait;

        memset(&max_wait, 0, sizeof(max_wait));

        /* wait at most 2 seconds */
        max_wait.tv_sec = 2;
        do_or_timeout(&max_wait);

        return 0;
}

你可以在linux上编译并运行它:

$ gcc test.c -pthread -lrt && ./a.out
do_or_timeout: calculation timed out

答案 1 :(得分:2)

如果你没有使用pthread,你也可以使用Apache Portable Runtime执行类似的超时功能:http://apr.apache.org/docs/apr/1.4/group__apr__thread__proc.html

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "apr.h"
#include "apr_thread_proc.h"
#include "apr_time.h"

void *APR_THREAD_FUNC expensive_call(apr_thread_t *thread, void *data)
{
    (void)thread;
    bool *done = data;

    /* ... calculations and expensive io here, for example:
     * infinitely loop
     */
    for (;;) {}

    // signal caller that we are done
    *done = true;
    return NULL;
}

bool do_or_timeout(apr_pool_t *pool, apr_thread_start_t func, int max_wait_sec)
{
    apr_thread_t *thread;
    bool thread_done = false;
    apr_thread_create(&thread, NULL, func, &thread_done, pool);
    apr_time_t now = apr_time_now();
    for (;;) {
        if (thread_done) {
            apr_thread_join(NULL, thread);
            return true;
        }
        if (apr_time_now() >= now + apr_time_make(max_wait_sec, 0)) {
            return false;
        }
        // avoid hogging the CPU in this thread
        apr_sleep(10000);
    }
}

int main(void)
{
    // initialize APR
    apr_initialize();
    apr_pool_t *ap;
    if (apr_pool_create(&ap, NULL) != APR_SUCCESS) {
        exit(127);
    }

    // try to do the expensive call; wait up to 3 seconds
    bool completed = do_or_timeout(ap, expensive_call, 3);
    if (completed) {
        printf("expensive_call completed\n");
    } else {
        printf("expensive_call timed out\n");
    }

    apr_terminate();
    return 0;
}

使用像这样的命令编译

gcc -o example example.c -lapr-1

答案 2 :(得分:1)

->include time.h 
->take two variable for start time & current time of type time_t
like time_t start_time,current_time
-> take start time 
   time(&start_time);
now in while loop continuisly check for 
   time(&current_time)
   difftime(current_time,start_time)
if difftime's return value is 15ms break while loop & close your program 

答案 3 :(得分:1)

我不知道那种架构,所以我只能给你一个一般性的提示。我会尝试类似于旧的Symbian TRAP机制。

  1. 在主程序中:

    • 启动计时器。
    • 收起堆栈指针
    • 收起一个程序柜台。
    • 打电话给你的功能。
  2. 在计时器异常(中断)处理例程中。 这有点棘手,因为当异常处理开始时,您需要知道给定的体系结构堆栈指针和程序计数器的位置(处理器的数据表)。程序计数器很可能被推送到主程序堆栈。 所以你的步骤是:

    • 用复制的值替换堆栈指针值(对于主例程)。
    • 用你复制的值+ offset代替程序计数器值(因为你想在函数调用后返回执行 - 最好检查汇编代码以确定它有多大)。
    • 从异常(中断)处理例程返回。

答案 4 :(得分:0)

@Bobby Powers的答案是可行的,但需要进行如下更改

if (!err)
    pthread_mutex_unlock(&calculating);
-> change to 
    pthread_mutex_unlock(&calculating);
as @T.D. Smith says

and need add  
pthread_cancel(tid) // if isn't add, the expensive_call may never exit if your function couldn't exit by itself, such as for (;;) {} or something block operation.