You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CPP互斥锁异常未触发自定义处理程序,调用Watson致无崩溃转储

std::shared_timed_mutex抛出的system_error未触发自定义异常处理的问题

问题场景

我们的代码存在如下死锁问题(简化版本):

std::shared_timed_mutex read_file_mutex;
std::shared_lock<std::shared_timed_mutex> read_file_lock(read_file_mutex
    , std::defer_lock);
if (read_file_lock.try_lock_for(std::chrono::milliseconds(200))) {
  ...
  ...
  if (read_file_lock.try_lock_for(std::chrono::milliseconds(200))) {

第二次调用try_lock_for时,MSVC的shared_mutex在验证阶段会抛出资源死锁的异常,符合预期:

void _Validate() const {
  // check if the mutex can be locked
  if (!_Pmtx)
    _THROW(system_error(
        _STD make_error_code(errc::operation_not_permitted)));
  if (_Owns)
    _THROW(system_error(
        _STD make_error_code(errc::resource_deadlock_would_occur)));
}

核心疑问

当上述异常触发时,为何会调用Watson处理程序而非我们注册的自定义无效参数异常处理程序?这导致程序终止且未生成崩溃转储。

已做的异常处理注册

我们已按文档注册了多种异常处理程序,其他类型异常均能正常触发自定义处理(在处理程序中生成崩溃转储),示例代码如下:

_invalid_parameter_handler old_handler, new_handler;

SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
new_handler = HandleInvalidParameter;
old_handler = _set_invalid_parameter_handler(new_handler);
_set_purecall_handler(PureVirtualCallHandler);

void (*rv)(int) = signal(SIGABRT, HandleAbortSignal);
_set_abort_behavior(0, 0);
EnableCrashingOnCrashes();
PreventSetUnhandledExceptionFilter();

环境说明

  • 32位软件运行于64位Windows 10系统
  • 编译器为clang

原因分析

  1. 异常类型不匹配:_set_invalid_parameter_handler仅处理C标准库或MSVC特定的无效参数异常(比如printf传入无效格式符触发的异常),而std::system_error属于C标准库抛出的**C异常**,不属于前者的处理范畴。
  2. 未捕获C++异常的默认行为:未捕获的std::system_error会触发std::terminate,默认情况下std::terminate会调用abort()触发SIGABRT信号,但如果STL内部抛出异常时直接绕过了自定义信号处理逻辑,就会触发Watson崩溃报告。
  3. Clang+MSVC STL的特殊行为:使用Clang编译但链接MSVC标准库时,部分STL内部抛出异常的路径可能直接调用Windows系统的崩溃处理逻辑,而非走你注册的自定义异常处理链。

解决方法

  1. 主动捕获C++异常:在可能抛出std::system_error的代码段外层添加try-catch块,主动捕获并触发自定义崩溃转储逻辑:
try {
  if (read_file_lock.try_lock_for(std::chrono::milliseconds(200))) {
    // ...业务代码
    if (read_file_lock.try_lock_for(std::chrono::milliseconds(200))) {
      // ...
    }
  }
} catch (const std::system_error& e) {
  // 调用自定义崩溃转储逻辑
  UnhandledExceptionHandler(nullptr);
}
  1. 替换std::terminate处理函数:通过std::set_terminate注册自定义终止处理程序,覆盖默认的std::terminate行为:
void CustomTerminateHandler() {
  // 执行崩溃转储逻辑
  UnhandledExceptionHandler(nullptr);
  // 确保程序终止
  abort();
}

// 在程序初始化阶段注册
std::set_terminate(CustomTerminateHandler);
  1. 修复死锁根源:最根本的方式是避免重复锁操作,在调用try_lock_for前检查锁状态:
if (read_file_lock.try_lock_for(std::chrono::milliseconds(200))) {
  ...
  ...
  // 仅在未持有锁时尝试加锁
  if (!read_file_lock.owns_lock() && read_file_lock.try_lock_for(std::chrono::milliseconds(200))) {
    // ...
  }
}

内容的提问来源于stack exchange,提问作者device_exec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 20:35:30