JOOF
JOOF

Reputation: 31

How to stop a function from running from outside in c++

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!

Upvotes: 1

Views: 5062

Answers (5)

Nicol Bolas
Nicol Bolas

Reputation: 474326

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.

Upvotes: 1

ObliteratedJillo
ObliteratedJillo

Reputation: 5166

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);
    }
}

Upvotes: 0

Trevir
Trevir

Reputation: 1313

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";
}

Upvotes: 3

Hatted Rooster
Hatted Rooster

Reputation: 36513

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.

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275878

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.

Upvotes: 0

Related Questions