使用 boost::lambda::bind 进行任意函数调用?

发布于 2024-12-28 20:36:13 字数 3660 浏览 1 评论 0原文

我必须使用一个 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(boost::packaged_task;(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) 几乎与我的 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::binds 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

丢了幸福的猪 2025-01-04 20:36:13

这行得通吗?

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

would this work?

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");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文