Произвольный вызов функции с boost :: lambda :: bind? - PullRequest
1 голос
/ 24 января 2012

Мне нужно использовать библиотеку extern, предоставляющую множество бесплатных функций, которые делают много сетевых вещей.Эта библиотека, к сожалению, не очень надежна, и в некоторых из этих функций она застревает навсегда (или, по крайней мере, очень долго).Для меня это не вариант, поэтому я хочу прервать вызов, если он занимает слишком много времени.

Взгляните на C ++: как реализовать тайм-аут для произвольного вызова функции? и boost::lambda библиотека, я придумал это:

#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

int foo(int a, int b) {
    boost::this_thread::sleep(boost::posix_time::seconds(2));
    return a+b;
}

int main() {
    int ret;
    boost::thread thrd(boost::lambda::var(ret) = boost::lambda::bind<int>(&foo, 1, 2));
    if(thrd.timed_join(boost::posix_time::seconds(1))) {
        std::cout << ret << std::endl;
    }
    else {
        std::cerr << "Function timed out." << std::endl;
    }
    return 0;
}

Компилируется и работает как шарм.Проблема, однако, в том, что у меня много функций с различными параметрами и возвращаемыми значениями, и написание вышеупомянутого для каждого случая кажется мне утомительной и избыточной работой.Поэтому я хочу обернуть его в функцию:

template <class t> t timeout(bindparam<t> &bind /* read below */, long sleep) {
    t ret;
    boost::thread thrd(boost::lambda::var(ret) = bind);
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) {
        return ret;
    }
    else throw std::runtime_error("timeout");
}

Идея состоит в том, что я могу запустить критическую функцию с помощью

try {
    int ret = timeout<int>(boost::lambda::bind<int>(&foo, 1, 2), 500);
    std::cout << ret << std::endl;
}
catch(std::runtime_error &e) {
    std::cerr << e.what() << std::endl;
}

, но я не знаю, как это сделать, иливозможно ли это вообще.Могу ли я как-нибудь передать произвольные boost::lambda::bind s в мою функцию?

Обновление:

Как и предполагалось, я попробовал это с boost::packaged_task:

template <class T> T timeout(boost::packaged_task<T> &f, long sleep) {
    T ret;
    boost::thread thrd(boost::lambda::var(ret) = f);
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) {
        return ret;
    }
    else {
        thrd.interrupt();
        throw std::runtime_error("timeout");
    }
}

Но когда я пытаюсь использовать его как timeout<int>(boost::packaged_task<int>(boost::bind(&foo, 1, 2)), 500);, я получаю странную ошибку компилятора:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:35: error: no matching function for call to ‘timeout(boost::packaged_task<int>, int)’

Не является ли timeout(boost::packaged_task<int>, int) почти полностью моей сигнатурой функции timeout, за исключениемint часть, которая будет преобразована неявно?Что я делаю не так?

Обновление 2:

Я наконец заставил его работать, но я понятия не имею, является ли то, что я делаю, хорошим способом сделатьэто потому, что мне было невероятно сложно найти какую-либо документацию или примеры по boost::packaged_task, и в основном все, с чем я работал, это исходный код библиотеки.Вот моя рабочая функция:

template <class T> T timeout(boost::packaged_task<T> &f, long sleep) {
    boost::thread thrd(boost::lambda::bind(&boost::packaged_task<T>::operator(), &f));
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) {
        boost::unique_future<T> ret = f.get_future();
        return ret.get();
    }
    thrd.interrupt();
    throw std::runtime_error("timeout");
}

Я не совсем доволен этим, в основном потому, что он не работает с временными, то есть вы должны пойти по этому пути, чтобы использовать его:

try {
    boost::packaged_task<int> f(boost::lambda::bind(&foo, 1, 2));
    int sum = timeout<int>(f, 500);
    std::cout << sum << std::endl;
}
catch(std::runtime_error &e) {
    std::cerr << e.what() << std::endl;
}

Я все равно был бы очень рад, если бы кто-то более искусный в этих структурах мог бы прокомментировать это.

1 Ответ

1 голос
/ 24 января 2012

будет ли это работать?

template <class T, class F>
T timeout(const F &bind, long sleep) {
    T ret;
    boost::thread thrd(boost::lambda::var(ret) = bind);
    if(thrd.timed_join(boost::posix_time::milliseconds(sleep))) {
        return ret;
    }
    else throw std::runtime_error("timeout");
}
...