1

I want to run a function and tell if the function didn't finish after n milliseconds, stop that function and start another one. something like this code:

void run()
{
    //do something that doesn't have while(1)
}


void main()
{
    run();
    if(runFunctionDidntFinishInSeconds(10)
    {
        endPrintFunction();
        backupPlan();
    }
    return 0;
}

I searched out and found boost::timed_join function. here's my code:

void run()
{
    int a;
    for (int i = 0; i < 2000; i++)
        cout << i << endl;
}


int main()
{
    boost::thread t = new boost::thread(&run);
    if (t.timed_join(boost::posix_time::microseconds(10000))){
        cout << "done" << endl;
    }
    else{
        cout << endl << "not done" << endl;
    }


    system("pause");
    return 0;
}

but it doesn't stop thread 't' from running. I went to terminate the thread, but it's not a good option. I want the 'a' function to finish the exact time I'm telling it to. The system gets input every 16ms and I want to do a processing on it and say if the processing took more than about 13ms leave it and go do a backup plan. and I want it to be abstracted from the ones who write the processing method. So putting a while loop on the top of it brings me delay. What should i do? The least I think I need is to be abled to reset the processing thread to do what it had needed to do again!

JOOF
  • 31
  • 1
  • 3
  • 1
    Another option is to have the loop depend on a global variable (`bool keep-running`) instead of being an infinite loop. Globals are generally bad practice, but in a case like this, they'll probably lead to cleaner code than the alternative. – Carcigenicate Sep 21 '16 at 14:57
  • 1
    Sounds like you need a condition variable. The function that keeps running checks the variable and if it is true then the function returns, otherwise it keeps running. Then you just need to set the variable when you wan the threads to end. – NathanOliver Sep 21 '16 at 14:57
  • the problem is the method I'm calling doesn't have a while(1) and I can't check for the variable in the middle of t like this and I want it to be abstracted from print method. – JOOF Sep 21 '16 at 15:06
  • @JOOF: This sounds very much like an XY problem. What are you trying to do that you think asynchronous termination of a function is a reasonable solution? – Nicol Bolas Sep 21 '16 at 15:39
  • @NicolBolas I have a system that gets input every 16ms and I want to do a processing on it and say if the processing took more than about 13ms leave it and go do a backup plan. and I want it to be abstracted from the ones who write the processing method. – JOOF Sep 21 '16 at 15:54
  • You sorta can do this with pthreads (pthread_kill and pthread_exit from the signal handler), but you are very restricted about what you can do in the thread you exit this way. Calling anything from the standard library is probably out. Don't even think about doing this with C++ threads. – n. m. could be an AI Sep 21 '16 at 16:00
  • If one thinks deeper, this question is a nice one. It will be difficult even to implement with a conditional variable. – seccpur Sep 21 '16 at 16:16
  • @JOOF: Put that information in your question. Also, that's not possible. – Nicol Bolas Sep 21 '16 at 17:55
  • Have you considered doing the backup and primary plan, with the primary plan in a different thread. If the primary plan hasn't delivered a result within the time frame you need, you use the already-computed backup plan? – Yakk - Adam Nevraumont Sep 21 '16 at 20:42
  • @Yakk yes I have. But I need to call the primary plan every 16milliseconds. Then there could be lots of threads computing the result i dont need and it decreases the performance of the program – JOOF Sep 23 '16 at 08:45

5 Answers5

3

I think your are looking for something like std::future.

http://en.cppreference.com/w/cpp/thread/future/wait_for

You can start the function in another thread and wait until the function returns or has a timeout.

For your example:

std::future< void > future = std::async( std::launch::async, print );

auto status = future.wait_for( std::chrono::seconds( 10 ) );
if ( status == std::future_status::deferred )
{
    std::cout << "deferred\n";
}
else if ( status == std::future_status::timeout )
{
    std::cout << "timeout\n";
}
else if ( status == std::future_status::ready )
{
    std::cout << "ready!\n";
}

However this doesn't cause the detached thread to end. For this it is necessary to include a flag on startup, so the detached thread can cleanup and exit savely on its own.

void run(const std::atomic_bool& cancelled)
{
    int a;
    for (int i = 0; i < 2000; i++)
    {
        cout << i << endl;
        if (cancelled)
            return;
    }
}

std::atomic_bool cancellation_token = false;
std::future< void > future = std::async( std::launch::async, 
                                         run,
                                         std::ref(cancellation_token) );

auto status = future.wait_for( std::chrono::seconds( 10 ) );
if ( status == std::future_status::deferred )
{
    std::cout << "deferred\n";
}
else if ( status == std::future_status::timeout )
{
    std::cout << "timeout\n";
    cancellation_token = true;
}
else if ( status == std::future_status::ready )
{
    std::cout << "ready!\n";
}
Trevir
  • 1,253
  • 9
  • 16
  • 1
    This will still keep the `std::async` alive even after the timeout expires though, the main thread will just continue. – Hatted Rooster Sep 21 '16 at 15:15
  • but how can I end the running function? – JOOF Sep 21 '16 at 15:18
  • Well, there is no save way to cancel the thread from outside once started. What is possible to include a cancellation flag in the startup, outlined in http://stackoverflow.com/a/33315162/6858837. – Trevir Sep 21 '16 at 15:23
  • problem is with my deadline. its 16millisecons and I can't delay in finishing it – JOOF Sep 21 '16 at 15:30
1

I want it to be abstracted from the ones who write the processing method.

Standard C++ does not have a way to forcibly interrupt the control flow of a function from outside of that function's call graph (a function it calls can throw, but someone can't throw for them).

OS-specific thread systems have ways to terminate a thread. However, this leaves the program potentially in an undefined state, as the destructors for any stack variables have not been called. And since you didn't know where it was in that processing when you killed it, you can't effectively clean up after it. Even a C program cannot guarantee that an arbitrary function can be terminated; it would have to be one which did not dynamically allocate memory or other resources that have to be cleaned up.

You can compensate for this by coding your function very carefully. But that requires that the person who wrote that function to code it very carefully. And thus, there isn't an abstraction, since the person writing the function has to know what the rules are and is required to follow them.

So the only solution that works requires cooperation. The function must either be written in such a way that it can safely be stopped via those OS-dependent features, or it must be written to periodically check some value and stop itself.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
0

Here are two and 3/4 approaches.

The first requires that the code you want to halt cooperates. It either polls some variable while it runs, or it calls a function periodically that could throw an exception to halt execution. boost interruptable threads follow the second model.

The second requires you to launch a new process, marshall your data over to the function, and use IPC to get the information back. If the function doesn't return in time, you kill the child process.

The third "half" involves rewriting the code in a different language, or using C++ as a scripting language. You run the code in an interpreter that does the first or second solution for you.


Now, a practical alternative (a 1/4 solution) is to make sure the function is purely functional, run it in a separate thread with a semi-reliable abort message (like the first one), and discard its return value if it takes too long. This doesn't do what you want, but is far easier.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • the problem is the deadline is 16millisecondes and I want it to be efficient and the function I'm calling is heavy & I'm doing it every 16milliseconds! – JOOF Sep 21 '16 at 15:12
0

There's a way with atomics used as semaphores but this will emit full blown memory barriers and thus decrease the performance because of the load every iteration :

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>

std::atomic<bool> printFinished { false };
std::atomic<bool> shouldPrintRun { true };

void print()
{
    while (shouldPrintRun.load() /* && your normal stop condition*/)
    {
        //work..
    }
    printFinished.store(true);
}


int main()
{
    std::thread t(print);
    std::this_thread::sleep_for(std::chrono::seconds(10));
    if (!printFinished.load())
    {
        shouldPrintRun.store(false);
        t.join();
        std::cout << "help!";
    }
    return 0;
}

If you don't want your function that's ran on another thread to check back if it needs to stop then terminating that thread is the only option.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • I want the print method ends exactly after I'm telling it. and the print function was just an example – JOOF Sep 21 '16 at 15:22
  • @JOOF That's not possible without terminating a `boost::thread`. – Hatted Rooster Sep 21 '16 at 15:23
  • @JOOF: How do you define "exactly"? You cannot end the execution of a function without that function's *consent*. Which requires you to somehow communicate with it. Which requires that function to *participate* in that communication. The only other alternative is OS thread termination. – Nicol Bolas Sep 21 '16 at 15:38
  • @NicolBolas I mean about after a short time(less than 1ms) – JOOF Sep 21 '16 at 15:56
0

A possible solution is that you have to make that the lengthy function into small & short incremental function which will continue the task still every time it is call from the last time it left of. The code below which can be run in a thread will do similar job of a time slicer and can be terminated at will.

void Process()
{       
    bool flag = true;
    while (running)
    {
        std::chrono::high_resolution_clock::time_point time1 = std::chrono::high_resolution_clock::now();
        std::chrono::milliseconds span(16);
        while ( (std::chrono::high_resolution_clock::now() - time1 ) < span)
        {
            flag ? incremental_function1() : incremental_function2();

            if (!running) return;
        }
        flag = (!flag);
    }
}
seccpur
  • 4,996
  • 2
  • 13
  • 21