2012-01-24 3 views
1

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

Взглянув на C++: How to implement a timeout for an arbitrary function call? и 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 моей функции?

Update:

Как было предложено, я попробовал с 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, которая будет преобразована неявно? Что я делаю не так?

Update 2:

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

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

I Would все еще очень рад, если кто-то, кто разбирается в этих структурах, может прокомментировать это.

+0

Почему бы просто не использовать 'boost :: packaged_task'? – Mankarse

+0

@Mankarse Честно говоря, потому что я никогда не слышал об этом. Я рассмотрю его. Благодарю. – nijansen

+0

@Mankarse Получил его для работы с boost :: packaged_task. Благодаря! – nijansen

ответ

1

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

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"); 
} 
+0

Как я могу назвать эту функцию? – nijansen

+0

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

+0

@Rob Kennedy Да, поток должен быть прерван в случае 'else'. Благодарю. – nijansen

Смежные вопросы