【发布时间】:2012-01-24 18:42:19
【问题描述】:
我必须使用一个 extern 库,它提供了许多免费功能,这些功能可以做很多网络工作。不幸的是,这个库不是很安全,而且它恰好永远卡在其中一些函数中(或者至少很长一段时间)。这对我来说不是一个选项,所以如果通话时间过长,我想中断通话。
看看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::binds 传递给我的函数吗?
更新:
按照建议,我尝试使用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)’
除了int 将被隐式转换的部分之外,timeout(boost::packaged_task<int>, int) 不正是我的timeout 函数签名吗?我做错了什么?
更新 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;
}
如果有更熟悉这些结构的人对此发表评论,我仍然会非常高兴。
【问题讨论】:
-
为什么不直接使用
boost::packaged_task? -
@Mankarse 老实说,因为我从未听说过。我会调查一下。谢谢。
-
@Mankarse 让它与 boost::packaged_task 一起工作。谢谢!
-
PS:也许将您的评论推广到答案,以便我可以为您提供信用?