该自己写重试而非用现成库的场景包括:嵌入式环境运行c++11、需精确控制退避策略(如100ms/200ms/400ms)、重试逻辑须与业务状态机耦合(如三次失败后切换备用通道)。

什么时候该自己写重试,而不是用现成库
多数场景下,libcurl、grpc 或 boost::asio 自带的重试机制够用;但如果你在嵌入式环境跑 C++11、或需要精确控制退避策略(比如失败后等 100ms,再等 200ms,再等 400ms),又或者重试逻辑要和业务状态机耦合(比如“重试三次失败就切换备用通道”),那就得手写——库往往太重或不可控。
用 std::function + 循环实现基础重试框架
核心是把任务包装成可调用对象,配合简单循环和延迟。不依赖第三方,C++11 起就能跑:
bool retry_until_success(std::function<bool> task, int max_attempts = 3, int base_delay_ms = 100) {
for (int i = 0; i <p>常见错误现象:<code>std::this_thread::sleep_for</code> 在某些实时系统上可能被信号中断,导致实际休眠时间远小于预期;若任务本身有副作用(如发包、写日志),重复执行前需确认幂等性。</p>
<ul>
<li><code>base_delay_ms * (1 是指数退避,避免雪崩式重试;线性退避用 <code>base_delay_ms * (i + 1)</code></code></li>
<li>若任务返回 <code>std::optional<t></t></code> 或 <code>std::expected<t e></t></code>(C++23),需改判空值或错误码,不能只看 <code>bool</code>
</li>
<li>别在循环里捕获 <code>std::exception</code> 后吞掉——至少记录 <code>what()</code>,否则失败时完全没线索</li>
</ul>
<h3>如何让重试感知错误类型并选择性放弃</h3>
<p>不是所有错误都值得重试:网络超时可以重试,404 或 401 就该立刻停。这时需把判断逻辑外移:</p>
<pre class="brush:php;toolbar:false;">bool should_retry(const std::exception& e) {
const char* msg = e.what();
return std::string_view(msg).find("timeout") != std::string_view::npos ||
std::string_view(msg).find("Connection refused") != std::string_view::npos;
}
使用场景:HTTP 客户端封装、串口通信、MQTT 连接建立。关键点在于——
- 不要硬编码字符串匹配,生产环境建议用枚举错误码或继承自
std::runtime_error的自定义异常类 -
std::system_category().default_error_condition可用于标准化系统错误(如EAGAIN、ETIMEDOUT),比字符串更可靠 - 若任务抛出异常,
retry_until_success必须用try/catch包裹,否则直接崩溃
避免重试逻辑污染业务代码的两种写法
直接在业务函数里塞 for 循环,很快会变成面条代码。推荐以下两种轻量解法:
方案一:用 RAII 封装重试上下文(适合短生命周期任务)
struct RetryContext {
int attempts = 0;
const int max_attempts;
RetryContext(int max) : max_attempts(max) {}
bool should_continue() { return ++attempts <p>方案二:模板化,支持任意签名(适合通用工具层)</p><pre class="brush:php;toolbar:false;">template<typename f typename... args>
auto retry_with_backoff(F&& f, Args&&... args) -> decltype(f(args...)) {
constexpr int max = 3;
for (int i = 0; i (args)...);
} catch (const std::exception& e) {
if (i == max - 1 || !should_retry(e)) throw;
std::this_thread::sleep_for(std::chrono::milliseconds(100 * (1 <p>容易踩的坑:模板推导可能失败,特别是当 <code>f</code> 返回 <code>void</code> 时,<code>decltype(f(...))</code> 会报错;此时需特化 <code>void</code> 版本,或改用 <code>std::invoke_result_t</code> + <code>if constexpr</code> 分支。</p>
<p>最常被忽略的是时钟精度——<code>std::chrono::milliseconds(100)</code> 在 Windows 上实际分辨率可能是 15ms,Linux 下也未必精确;对毫秒级敏感的场景,得用 <code>std::chrono::high_resolution_clock</code> 校准休眠起点,而非依赖 sleep_for 的理论值。</p></typename>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











