C++ initonceExecutionce异常安全

C++ initonceExecutionce异常安全,c++,winapi,initialization,exception-safety,C++,Winapi,Initialization,Exception Safety,我在initonceExecutionce WinAPI函数上有一个异常安全问题。无论何时从回调函数引发异常,都会发生死锁。Callback返回布尔标志,告诉调用者数据是否已成功初始化,但如果返回false,则无法重新显示异常,这不好。我试着用这种方法解决这个问题 try { InitOnceExecuteOnce(&flag, init_once_handler, &arguments, 0); } catch (...) { InitOnceInitializ

我在initonceExecutionce WinAPI函数上有一个异常安全问题。无论何时从回调函数引发异常,都会发生死锁。Callback返回布尔标志,告诉调用者数据是否已成功初始化,但如果返回false,则无法重新显示异常,这不好。我试着用这种方法解决这个问题

try
{
    InitOnceExecuteOnce(&flag, init_once_handler, &arguments, 0);
} catch (...)
{
    InitOnceInitialize(&flag);
    throw;
}
每当我从函数中捕获异常时,我都会再次初始化结构并重新抛出异常,这样其他线程就会发现数据未初始化,因为标志处于初始状态。然而,它有时也会死锁,可能是因为在第一个线程捕获异常并再次初始化标志之前,其他线程开始等待同步对象。那个问题有什么解决办法吗


谢谢。

< P>不应该通过代码不期望的代码来抛出C++异常,例如C代码,或者在你的例子中,Windows API。取而代之的是,回调错误返回错误,这将反映在从INTIOCEXECUTETE返回“

> P>”中,您不应该通过不期望的代码抛出C++异常,例如C代码,或者在Windows Windows API中。相反,在出现错误时让回调返回false,这将反映在InitOnceExecuteOnce的返回中。这是一个用户定义的函数,我不能保证。这是一个C++代码,它使用容器、算法,每一步都可能有例外,我应该做的是避免在这个函数执行的结果中出现问题,并且我也想把异常传播给调用方,但是这会导致死锁。也许还有另一种机制允许这样做?@axe:如果是这样,用你自己的回调包装该回调,你的回调捕获异常并返回false。您可以选择将函数的参数包装在一个结构中,允许您从回调中返回有关异常的信息。我已经完成了这项工作,我还使用polymorph类包装了异常对象,该类会重新引发异常,例如boost::current_exception,但这只允许我重新引发预定义的异常集,若用户抛出某个用户定义的类对象,他将捕获std::runtime\u errorunknown异常。很好,但可能更好。@axe:如果你不能保证,那就享受你的僵局吧。如果要避免死锁,请在回调函数中捕获异常,将异常保存在某个位置,例如使用上下文参数,然后返回错误代码。如果InitOnceExecuteOnce返回该错误代码,则获取保存的异常副本并重新播放它。使用异常包装完成。谢谢大家。这是一个用户定义的函数,我不能保证。这是一个C++代码,它使用容器、算法,每一步都可能有例外,我应该做的是避免在这个函数执行的结果中出现问题,并且我也想把异常传播给调用方,但是这会导致死锁。也许还有另一种机制允许这样做?@axe:如果是这样,用你自己的回调包装该回调,你的回调捕获异常并返回false。您可以选择将函数的参数包装在一个结构中,允许您从回调中返回有关异常的信息。我已经完成了这项工作,我还使用polymorph类包装了异常对象,该类会重新引发异常,例如boost::current_exception,但这只允许我重新引发预定义的异常集,若用户抛出某个用户定义的类对象,他将捕获std::runtime\u errorunknown异常。很好,但可能更好。@axe:如果你不能保证,那就享受你的僵局吧。如果要避免死锁,请在回调函数中捕获异常,将异常保存在某个位置,例如使用上下文参数,然后返回错误代码。如果InitOnceExecuteOnce返回该错误代码,则获取保存的异常副本并重新播放它。使用异常包装完成。谢谢大家。