C++中控制函数调用超时

有时候调用别人的程序一直不返回,造成卡死,后续程序无法处理,比如,我们通过grpc_client来连接仿真服务器,但是在生成env = new Environment(ipAddress)的时候,一直不返回,后续我们无法处理。所以,我想着怎么控制该调用在一定时间内返回或者超时处理。对于这种情况,我们无法使用多次尝试的方式,因为代码不是我们的,我们无法进入里面设置超时等。经过调研,基本的可行方式是将该函数调用扔到一个线程中,通过线程超时来控制该函数调用。主要有两种方式,一种使用C++ 11提供的标准方式,一种使用boost库。

可以生成boost::thread来调用API:

boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
    // API call returned within 500ms
}
else
{
    // API call timed out
}

但是,Boost不允许您终止工作线程。在此示例中,它只是孤立的。

您必须注意该API调用的作用,因为它可能永远不会释放所获取的资源。

或者使用条件变量:

#include "boost/thread.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/condition.hpp"
#include "boost/date_time/posix_time/posix_time.hpp"
//----------------------------------------------------------
boost::mutex g_mutexWait;               // 互斥锁
boost::condition_variable g_condWait;   // 条件变量
//----------------------------------------------------------
///< 输入数据线程函数
void InputThread()
{
    std::cout << "请在10秒内输入任意字符:" << std::endl;
    // 等待手工输入
    std::string strInputData = "";
    std::cin >> strInputData;
    // 输入了字符,则发出通知
    if (strInputData != "")
    {
        g_condWait.notify_one();
    }
}
//----------------------------------------------------------
///< 主函数
int main(int argc, char* argv[])
{
    try
    {
        // 启动线程输入数据
        boost::thread threadInput(InputThread);
        // 取得当前时间
        time_t tmInputStart = time(NULL);
 
        // 使用条件变量,等待输入数据
        //boost::unique_lock<boost::mutex> lockWait(g_mutexWait);
        boost::mutex::scoped_lock lockWait(g_mutexWait);
        bool bRet = g_condWait.timed_wait(lockWait, boost::get_system_time() + boost::posix_time::seconds(10));
        // 消息接收超时
        if (bRet == false)
        {
            std::cout << "您输入的太慢了!请输入任意字符退出程序!" << std::endl;
        }
        else // 接收到条件变量信号,未超时
        {
            time_t tmInputEnd = time(NULL);
            std::cout << "您输入的太快了!只用了" << (tmInputEnd - tmInputStart) << "秒!" << std::endl;
        }
        // 等待线程退出
        threadInput.join();
    }
    catch (std::exception &ex)
    {
        std::cout << ex.what() << std::endl;
    }
    system("PAUSE");
    return 0;
}
//----------------------------------------------------------

使用C++ 11的标准库:

#include <stdlib.h>
#include <string>
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
//----------------------------------------------------------
std::mutex g_mutexWait;                 // 互斥锁
std::condition_variable g_condWait;     // 条件变量
//----------------------------------------------------------
///< 输入数据线程函数
void InputThread()
{
    std::cout << "请在10秒内输入任意字符:" << std::endl;
    // 等待手工输入
    std::string strInputData = "";
    std::cin >> strInputData;
    // 输入了字符,则发出通知
    if (strInputData != "")
    {
        g_condWait.notify_one();
    }
}
//----------------------------------------------------------
///< 主函数
int main(int argc, char* argv[])
{
    try
    {
        // 启动线程输入数据
        std::thread threadInput(InputThread);
        // 取得当前时间
        time_t tmInputStart = time(NULL);
 
        // 使用条件变量,等待输入数据
        std::unique_lock<std::mutex> lockWait(g_mutexWait);
        std::cv_status cvsts = g_condWait.wait_for(lockWait, std::chrono::seconds(10));
        // 消息接收超时
        if (cvsts == std::cv_status::timeout)
        {
            std::cout << "您输入的太慢了!请输入任意字符退出程序!" << std::endl;
        }
        else // 接收到条件变量信号,未超时
        {
            time_t tmInputEnd = time(NULL);
            std::cout << "您输入的太快了!只用了" << (tmInputEnd - tmInputStart) << "秒!" << std::endl;
        }
        // 等待线程退出
        threadInput.join();
    }
    catch (std::exception &ex)
    {
        std::cout << ex.what() << std::endl;
    }
    system("PAUSE");
    return 0;
}
//----------------------------------------------------------

 

C++ 中,**实现一个函数调用超时后返回**是一个非常常见的需求,尤其是在网络请求、异步任务处理或资源加载等场景中。由于标准库不提供直接取消函数执行的机制,因此我们需要借助多线程和同步控制来模拟“超时返回”。 --- ## ✅ 实现目标 我们希望实现如下功能: ```cpp int result = call_with_timeout(my_function, 3s); ``` - 如果 `my_function()` 在 **3 秒内完成**,则返回其结果; - 如果 **超过 3 秒未完成**,则中断该函数并返回一个特定值(如 `-1` 或抛出异常); --- ## ✅ 实现原理 我们将使用以下组件: - `std::thread`:用于异步执行函数; - `std::promise` + `std::future`:在线程之间传递函数执行结果; - `std::atomic<bool>`:作为中断标志; - `std::condition_variable`:等待或通知主线程是否完成; - 超时检测逻辑:主线程等待指定时间,若未完成则取消。 --- ## ✅ 示例代码(支持返回值) ```cpp #include <iostream> #include <thread> #include <chrono> #include <future> #include <atomic> #include <functional> #include <stdexcept> using namespace std::chrono_literals; // 通用模板函数:带超时函数调用器 template<typename Func, typename... Args> auto call_with_timeout(Func func, std::chrono::milliseconds timeout, Args&&... args) -> std::future<typename std::invoke_result<Func, Args...>::type> { using return_type = typename std::invoke_result<Func, Args...>::type; std::shared_ptr<std::promise<return_type>> p = std::make_shared<std::promise<return_type>>(); std::atomic<bool> done(false); std::thread([p, &done, func, timeout, &args...]() mutable { std::thread worker([p, func, &args...]() { try { p->set_value(func(args...)); } catch (...) { p->set_exception(std::current_exception()); } done = true; }); // 等待工作线程完成或被外部取消 while (!done.load()) { std::this_thread::sleep_for(100ms); } if (worker.joinable()) { worker.detach(); // 不再关心它是否结束 } }).detach(); return p->get_future(); } ``` --- ## ✅ 使用示例 ```cpp #include <iostream> #include <chrono> #include <future> #include <thread> int long_running_task(int x) { std::this_thread::sleep_for(std::chrono::seconds(5)); // 模拟耗时操作 return x * x; } int main() { auto future = call_with_timeout(long_running_task, 3s, 42); std::cout << "Waiting for result...\n"; auto status = future.wait_for(3s); if (status == std::future_status::ready) { std::cout << "Result: " << future.get() << "\n"; } else { std::cout << "Function timed out!\n"; } return 0; } ``` --- ## ✅ 输出示例 ``` Waiting for result... Function timed out! ``` --- ## 🔍 注意事项 - 本方案是 **模拟中断**,不是真正终止线程执行,只是让主线程不再等待; - 如果你需要真正终止线程,必须在函数内部定期检查中断标志(如 `std::atomic<bool>`),并在适当位置提前返回; - 若你使用的是 C++20,可以考虑使用 `std::jthread` 和 `std::stop_token` 来更优雅地支持取消。 --- ## ✅ 带中断标志版本(主动停止任务) 如果你希望函数能响应取消信号,可以修改为如下形式: ```cpp int cancellable_task(std::atomic<bool>& stop_flag) { for (int i = 0; i < 10 && !stop_flag.load(); ++i) { std::this_thread::sleep_for(1s); std::cout << "Working... Step " << i + 1 << "/10\n"; } if (stop_flag.load()) { throw std::runtime_error("Task was cancelled"); } return 42; } ``` 然后你可以结合上面的 `call_with_timeout` 并在主线程中设置 `stop_flag = true` 来提前退出任务。 --- ##
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值