views:

66

answers:

1

Hi,

I'm trying to develop a program to time limit the execution of a function. In the code below I have a function named Inc which does a lot of iterations (simulated by the infinite loop). The first part of each iteration is quite long, followed by a second part that should be pretty fast.

I don't mind preempting the execution while in the first part of the code, but I'd like to avoid the alarm going off while doing a write operation on the second part.

My first idea was to turn off the alarm before entering the 'safe region' saving the remaining time. Then after exiting, I would set the alarm up with the saved time. I don't know how to implement this. Could someone help me? Alternative methods are also welcome.

#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");
}
+3  A: 

The obvious thing is to take a lock before calling pthread_cancel, and to hold the same lock across your "safe region".

Unfortunately, you can't wait on a mutex or a semaphore in a signal handler. But alarm signals aren't the only way to do something after 10 seconds - you could instead have your main thread go to sleep for 10 seconds, then wake up, take the lock, cancel the worker thread and then join it.

Of course this would mean that the main thread will sleep 10 seconds even if the worker thread finishes after 5 seconds. So instead of sleeping, have the main thread do a 10 second timed wait on a semaphore, which the worker thread posts when it finishes.

Like a sleep, a timed wait can complete early due to a signal, so be sure to retry the timed wait on EINTR. Your significant cases are EINTR (wait again), success (join the worker thread - no need to cancel since it has posted the semaphore), ETIMEDOUT (take the lock, cancel, join) and if you like, other errors. There are no other errors listed for sem_timedwait that should affect you, though.

Another idea is to block SIGALRM across your "safe region", which would be simpler except that (a) I can never remember how to safely do I/O with signals disabled, and (b) your worker thread could probably be running "simultaneously" with the signal handler (either truly simultaneous or apparently so due to pre-emption), meaning that the signal could be taken, then your worker disables signals and enters the critical region, then the signal handler cancels it. If nobody answers who can actually remember the details, here's some information on blocking signals.

Steve Jessop
Sorry, I couldn't understand almost anything from what you said. I have little knowledge on operational systems. Using timed wait seems a good approach, but can you offer some references? thanks!
kunigami
Not easily. If you don't understand what locks, semaphores, and mutexes are, then start with an introduction to programming with pthreads and semaphores (for instance https://computing.llnl.gov/tutorials/pthreads/, http://en.wikipedia.org/wiki/Semaphore_%28programming%29, http://www.opengroup.org/onlinepubs/000095399/basedefs/semaphore.h.html). Once you understand the basics, I think that what I've written should make sense.
Steve Jessop