使用 boost::lambda::bind 进行任意函数调用?
我必须使用一个 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
传递给我的函数吗?
更新:
按照建议,我尝试使用 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
我收到一个奇怪的编译器错误:
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
几乎与我的 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;
}
如果更擅长这些结构的人可以发表评论,我仍然会非常高兴这。
I have to use an extern library providing lots of free functions that do a lot of networking stuff. This library, unfortunately, is not very failsafe, and it happens to get stuck in some of these functions forever (or at least a very long time). This is not an option for me, so I want to interrupt the call if it is taking too long.
Taking a look at C++: How to implement a timeout for an arbitrary function call? and the boost::lambda
library, I came up with this:
#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;
}
Compiles and works like a charm. The problem however is, that I have lots of functions with different parameters and return values, and writing the above for every case seems like tedious and redundant work to me. So I want to wrap it in a function:
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");
}
The idea is that I can run the critical function with
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;
}
but I have no idea how to do this, or whether it is even possible. Can I pass arbitrary boost::lambda::bind
s to my function somehow?
Update:
As suggested, I tried it with 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");
}
}
But when I try to use it as timeout<int>(boost::packaged_task<int>(boost::bind(&foo, 1, 2)), 500);
I get a strange compiler error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:35: error: no matching function for call to ‘timeout(boost::packaged_task<int>, int)’
Isn't timeout(boost::packaged_task<int>, int)
pretty much exactly my function signature of timeout
, except for the int
part that will be converted implicitly? What am I doing wrong?
Update 2:
I finally got it to work, but I have no idea whether what I am doing is a good way of doing it, because I found it incredibly hard to find any documentation or examples on boost::packaged_task
and basically all I worked with is the source code of the library. Here is my working function:
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");
}
I am not completely happy with it, mainly because it does not work with temporaries, meaning you have to go this way to use it:
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 still be very happy if someone more adept with these structures could comment on this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这行得通吗?
would this work?