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

144 篇文章 6 订阅

有时候调用别人的程序一直不返回,造成卡死,后续程序无法处理,比如,我们通过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;
}
//----------------------------------------------------------

 

  • 11
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在 Linux 实现 C 语言的超时检测有多种方法,这里介绍两种: 1. 基于 select 函数的超时检测 通过 select 函数可以将多个文件描述符和超时时间传入,函数会检测这些文件描述符是否准备好进行读或写,并设定一个超时时间。如果在超时时间内没有任何一个文件描述符准备好,则 select 函数返回 0。如果准备好的文件描述符数量大于 0,则 select 函数返回准备好的文件描述符数量。 使用 select 函数进行超时检测的一般流程如下: ```c fd_set fdset; struct timeval timeout; FD_ZERO(&fdset); /* 清空文件描述符集合 */ FD_SET(fd, &fdset); /* 设置要检测的文件描述符 */ timeout.tv_sec = seconds; /* 设置超时时间,单位为秒 */ timeout.tv_usec = 0; /* 调用 select 函数进行超时检测 */ if (select(fd + 1, &fdset, NULL, NULL, &timeout) == 0) { /* 超时未发生 */ } else { /* 超时发生或文件描述符准备就绪 */ } ``` 2. 基于 alarm 函数的超时检测 通过 alarm 函数可以定时向进程发送一个 SIGALRM 信号,可以设定一个定时器,在定时器时间到达时向进程发送 SIGALRM 信号。在程序可通过注册一个 SIGALRM 信号处理函数来处理此信号。通过 alarm 函数实现超时检测的流程如下: ```c void timeout_handler(int sig) { /* 超时处理逻辑 */ } signal(SIGALRM, timeout_handler); /* 注册 SIGALRM 信号处理函数 */ alarm(duration); /* 设定定时器,duration 为超时时间,单位为秒 */ /* 调用需要超时检测的函数 */ function_to_check_timeout(); alarm(0); /* 取消定时器,避免影响其他函数操作 */ ``` 需要注意的是,在使用 alarm 函数时,需要确保被调用的函数不会阻塞同步信号,否则在超时时间到达后可能会发生不可预测的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值