Как установить ограничение по времени для функции с защищенной областью - PullRequest
1 голос
/ 02 сентября 2010

Я пытаюсь разработать программу, чтобы ограничить время выполнения функции. В приведенном ниже коде у меня есть функция с именем Inc, которая выполняет много итераций (моделируется бесконечным циклом). Первая часть каждой итерации довольно длинная, за которой следует вторая часть, которая должна быть довольно быстрой.

Я не возражаю против прерывания выполнения в первой части кода, но я бы хотел избежать срабатывания сигнализации при выполнении операции записи для второй части.

Моей первой идеей было отключить будильник перед входом в «безопасный регион», сохранив оставшееся время. Затем после выхода я установил будильник с сохраненным временем. Я не знаю, как это реализовать. Может ли кто-нибудь помочь мне? Альтернативные методы также приветствуются.

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

pthread_t thread;
FILE *fout;

void *Inc(void *param){

    int i;
    long long int x = 0;

    fout = fopen("file.txt", "w");

    /* Large number of iterations */
    while(1){

        int k = 0;
        for(i=0; i<5000000; i++)
            k += (rand())%3;
        x += k;

        printf("%lld\n", x);
        /* Enter Safe Region */
        fprintf(fout, "%lld\n", x);
        /* Exit Safe Region */
    }   
}

void Finish(int param){
    pthread_cancel(thread);
    fclose(fout);
}

main (){

    pthread_attr_t attr;
    void *status;

    signal(SIGALRM, Finish);
    alarm(10);

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    pthread_create(&thread, &attr, Inc, NULL);
    pthread_attr_destroy(&attr);
    pthread_join(thread, &status);

    printf("Program Finished\n");
}

1 Ответ

3 голосов
/ 02 сентября 2010

Очевидная вещь - взять блокировку перед вызовом pthread_cancel и удерживать такую ​​же блокировку в вашем «безопасном регионе».

К сожалению, вы не можете ждать мьютекса или семафора в обработчике сигналов. Но сигналы тревоги - не единственный способ сделать что-то через 10 секунд - вместо этого вы можете перевести основной поток в режим сна на 10 секунд, а затем проснуться, снять блокировку, отменить рабочий поток и затем присоединиться к нему.

Конечно, это будет означать, что основной поток будет спать 10 секунд, даже если рабочий поток завершит работу через 5 секунд. Поэтому вместо того, чтобы спать, основной поток должен сделать 10-секундное время ожидания для семафора, который рабочий поток публикует после завершения.

Как и во сне, таймерное ожидание может завершиться рано из-за сигнала, поэтому обязательно повторите таймерное ожидание на EINTR. Ваши существенные случаи: EINTR (снова ждать), успех (присоединиться к рабочему потоку - нет необходимости отменять, поскольку он опубликовал семафор), ETIMEDOUT (снять блокировку, отменить, объединить) и, если хотите, другие ошибки. Однако для sem_timedwait нет других ошибок, которые могут повлиять на вас.

Другая идея состоит в том, чтобы блокировать SIGALRM в вашем «безопасном регионе», что было бы проще, за исключением того, что (а) я никогда не могу вспомнить, как безопасно выполнять ввод-вывод с отключенными сигналами, и (б) ваш рабочий поток, вероятно, мог бы быть запуск «одновременно» с обработчиком сигнала (либо действительно одновременным, либо, очевидно, таковым из-за упреждения), что означает, что сигнал может быть принят, затем ваш работник отключает сигналы и входит в критическую область, затем обработчик сигналов отменяет его. Если никто не отвечает, кто на самом деле может запомнить детали, вот некоторая информация о блокирующих сигналах .

...