Linux 解决调用函数超时方法

Publish: August 2, 2016 Category: C/C++ No Comments

当我们需要一个别人写的一个函数(可能是库里的),但是该函数可以会执行很长的时间,我们需要对其做超时控制,最简单的方法是使用alarm + signal的处理方式,但是在信号的处理函数中能做的比较少,只能做一些简单的处理,这里提供另外一种方法:

原理:使用线程的 pthread_cond_timedwait() 方法,主线程创建子线程并使用 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
         */
        int i = 0;
        for (;;) {
            printf("%d\n", i); 
            sleep(1);
            i++;
        }   
        /* 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 = 5;
        do_or_timeout(&max_wait);
        printf("Finish\n");
        return 0;
}


编译与执行:

$ gcc -g -o test test.c -pthread -lrt
$ ./test