Как завершить вызов функции после тайм-аута? - PullRequest
1 голос
/ 06 февраля 2020

Допустим, у меня есть функция foo (). Я хочу, чтобы он работал, например, через 5 секунд, после этого его нужно отменить и продолжить делать остальную часть программы.

Фрагменты кода:

int main() {
    // Blah blah
    foo(); // Running in 5 sec only
    // After 5 sec, came here and finished
}

Ссылки : Через некоторое время поиска в StackOverflow я обнаружил, что это то, что мне нужно, но записано в python: Время ожидания при вызове функции .

signal.h и unistd.h могут быть связаны .

Ответы [ 3 ]

1 голос
/ 06 февраля 2020

Это возможно с потоками. Начиная с C ++ 20, это будет довольно просто:

{
    std::jthread t([](std::stop_token stoken) {
        while(!stoken.stop_requested()) {
            // do things that are not infinite, or are interruptible
        }
    });

    using namespace std::chrono_literals;
    std::this_thread::sleep_for(5s);
}

Обратите внимание, что многие взаимодействия с операционной системой приводят к "блокировке" процесса. Примером этого является функция POSIX listen, которая ожидает входящих соединений. Если поток заблокирован, то он не сможет перейти к следующей итерации.

К сожалению, стандарт C ++ не определяет, должны ли такие вызовы платформы, указанные c, прерываться запросом на остановку или не. Вам нужно использовать методы, определяемые платформой c, чтобы убедиться, что это произойдет. Как правило, сигналы могут быть настроены на прерывание системных вызовов. В случае listen можно подключиться к ожидающему сокету.

1 голос
/ 06 февраля 2020

Нет способа сделать это единообразно в C ++. Существуют способы сделать это с некоторой степенью успеха, когда вы используете API, специфицированные для ОС c, однако все это становится чрезвычайно громоздким.

Основная идея c, которую вы можете использовать в * nix, является комбинацией alarm() системный вызов и setjmp/longjmp C функция.

A (псевдо) код:

std::jmp_buf jump_buffer;

void alarm_handle(int ) {
    longjmp(jump_buffer);
}

int main() {
   signal(SIGALRM, alarm_handle); 
    alarm(5);
    if (setjmp(jump_buffer)) {
        foo(); // Running in 5 sec only
     } else {
        // After 5 sec, came here and finished
        // if we are here, foo timed out
     } 
}

Все это чрезвычайно fr agile и шатко (то есть длинные прыжки не подходят для времени жизни объектов C ++), но если вы знаете, что Вы делаете это может работать.

0 голосов
/ 06 февраля 2020

Совершенно стандартный C ++ 11

#include <iostream>
#include <thread>         // std::this_thread::sleep_for
#include <chrono>         // std::chrono::seconds

using namespace std;

// stop flag
bool stopfoo;

// function to run until stopped
void foo()
{
    while( ! stopfoo )
    {
        // replace with something useful
        std::this_thread::sleep_for (std::chrono::seconds(1));
        std::cout << "still working!\n";
    }
    std::cout "stopped\n";
}

// function to call a top after 5 seconds
void timer()
{
    std::this_thread::sleep_for (std::chrono::seconds( 5 ));
    stopfoo = true;
}

int main()
{
    // initialize stop flag
    stopfoo = false;

    // start timer in its own thread
    std::thread t (timer);

    // start worker in main thread
    foo();

    return 0;
}

Это то же самое, что и флаг остановки потока (не обязательно, но рекомендуется для более сложных случаев)

#include <iostream>
#include <thread>         // std::this_thread::sleep_for
#include <chrono>         // std::chrono::seconds
#include <mutex>

using namespace std;

class cFlagThreadSafe
{
public:
    void set()
    {
        lock_guard<mutex> l(myMtx);
        myFlag = true;
    }
    void unset()
    {
        lock_guard<mutex> l(myMtx);
        myFlag = false;
    }
    bool get()
    {
         lock_guard<mutex> l(myMtx);
         return myFlag;
    }
private:
    bool myFlag;
    mutex myMtx;
};

// stop flag
cFlagThreadSafe stopfoo;

// function to run until stopped
void foo()
{
    while( ! stopfoo.get() )
    {
        // replace with something useful
        this_thread::sleep_for (std::chrono::seconds(1));
        cout << "still working!\n";
    }
    cout << "stopped\n";
}

// function to call a top after 5 seconds
void timer()
{
    this_thread::sleep_for (chrono::seconds( 5 ));
    stopfoo.set();
}

int main()
{
    // initialize stop flag
    stopfoo.unset();

    // start timer in its own thread
    thread t (timer);

    // start worker in main thread
    foo();

    t.join();

    return 0;
}

И если все нормально в главном потоке, все может быть значительно упрощено.

#include <iostream>
#include <thread>         // std::this_thread::sleep_for
#include <chrono>         // std::chrono::seconds

using namespace std;

void foo()
{
    auto t1 = chrono::steady_clock ::now();

    while( chrono::duration_cast<chrono::seconds>(
                chrono::steady_clock ::now() - t1 ).count() < 5 )
    {
        // replace with something useful
        this_thread::sleep_for (std::chrono::seconds(1));
        cout << "still working!\n";
    }
    cout << "stopped\n";
}

int main()
{
    // start worker in main thread
    foo();

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...