待機中のスレッドでブーストミューテックスに例外をスローさせる方法はありますか? オブジェクトが削除されるという問題がありますが、ソフトウェア ライブラリの性質上、オブジェクト内のミューテックスでスレッドが待機している可能性があり、ミューテックスが閉じられたときに厄介な例外がスローされる可能性があります。複数のミューテックスカウンターを使用できると思いますが、パフォーマンスが低下する可能性があります。私が望んでいるのは、スタックがアンロールされるように、ミューテックスが閉じられたときに待機しているスレッドで例外をスローすることです。プラットフォームに依存しない、これを行うためのクリーンな方法はありますか?
1 に答える
破壊されたときにスローするミューテックスのこのような概念は無害に思えますが、実装する段階になると、ミューテックスについての考え方に欠陥があることが明らかになります。
このようなアプローチの落とし穴を理解するために、いくつかのサンプル コードを見てみましょう。
注:以下のコードは使用しないでください。これを使用すると、無限の苦痛と同期の問題のデバッグに苦しむことになります。
class throwing_mutex
{
private:
mutex m_;
condition_variable cv_;
bool destroyed_;
bool locked_;
public:
void lock()
{
std::unique_lock<std::mutex> lock(m_);
cv_.wait(lock, [&]() {return !locked_ || destroyed_;}); // Wait until the mutex is unlocked or destroyed.
if (destroyed_) throw runtime_error("The exception was terminated while waiting.");
locked_ = true;
}
void unlock()
{
std::unique_lock<std::mutex> lock(m_);
locked_ = false;
lock.unlock();
cv_.notify_one();
}
~throwing_mutex()
{
std::unique_lock<std::mutex> lock(m_);
destroyed_ = true;
lock.unlock();
cv_.notify_all(); // Let all waiters know we are dead.
}
};
破壊されると、ウィルを待っているすべての人にthrowing_mutex
例外がスローされます。しかし、これはかなり大きな競合状態を引き起こします。
誰もがミューテックスを待っているケースを処理しました - 彼らは安全にスローします。私たちが扱っていないのは、誰かが電話をかけようとしているlock()
が、まだ完了していない場合です。彼らが最終的に を呼び出すことができるようlock()
になったとき、throwing_mutex
はすでに破壊されています。欠陥のある方法論によって導入されたバグは、use-after-freeと呼ばれます。運が良ければ、エラーは早期かつ明確に表示されますが、それほど運が悪く、何時間も何日も苦しめられることもあります。私たちのクラスがその問題を解決できる方法はなく、そのthrowing_mutex
ようなクラスを必要とするコードには、所有権のセマンティクスがよく考えられていません。
では、スローするミューテックスを使用しない場合、この問題をどのように解決すればよいでしょうか? ミューテックスとそれによってロックされているオブジェクトの有効期間を修正します。
おそらく、これはミューテックスがクラスのメンバーです。その場合、オブジェクトに依存しているすべての人がそれを使い果たすまで、破棄を遅らせることを意味します。これは を使用して伝えられshared_ptr
ます。所有権のセマンティクスの核心に入ることなく、これが答えられる最善の方法です。願わくば、私が問題に対するあなたの考え方を十分に変えて、あなたを元の計画から遠ざけ、より確実に機能する何かに向けさせてください。