私は最近std :: mutexを使用していて、メンバとしてstd :: mutexを持つオブジェクトを削除する際のパターン/デザインガイドを探しています。この問題は、ミューテックス(モニタ関数、クリティカルセクションなど)を使用する公開関数としてのオブジェクトが存在し、このオブジェクトが削除されたときにスレッドがミューテックスを待機している可能性があります。 std :: mutexは未定義の動作を他のスレッドによってロックされている間に削除してしまい、問題が発生します。メンバstd :: mutexを安全に削除する方法?
この場合、一般に受け入れられるパターンが何であるか知りたいです。あるいは、これが悪いコーディングスタイルとみなされた場合、この設計を避ける方法、すなわち、mutexメソッドがまだ待っているオブジェクトを削除しないでください。
例:
//a public method that uses mutex.
IAsyncAction^ XInputBase::flushTask()
{
return create_async([this](){
_monitorMutex.lock();
if (_readyToFlush && !_noMoreFlush) {
//should flush only once, block additional flush signals.
_noMoreFlush = true;
_monitorMutex.unlock();
//actually flush
concurrency::task<void> UITask = concurrency::create_task(Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,
ref new Windows::UI::Core::DispatchedHandler([=]()
{
onFlush();
})));
}
else {
_needToFlush = true;
_monitorMutex.unlock();
}
});
}
しようとしたソリューション: デストラクタは、すべての待機中のスレッドが処理された後、完全にロックを解除するためにミューテックスを待っています。私はmutexの外側にフラグを設定して実装しました。そのため、メソッド内のすべてのスレッドは、ミューテックスを終了するか待機します。その後、私はstd :: mutexをデストラクタで最後にロックしました。 std :: mutexが公平であるとすれば、他の待機中のスレッドが処理された後でデストラクターを最後にアンロックし、オブジェクトを破棄する必要があります。
std :: mutexはほとんどのプラットフォームで公平性を保証していないため、これは機能しません。
解決策のソート: オブジェクトをrefクラスまたは他の参照カウントオブジェクト(スマートポインタ)として実装します。その後、オブジェクトへの強い参照を保持するラムダとして並行メソッドを実装します。このオブジェクトを保持する他のすべてのオブジェクトが削除され、mutexを持つすべてのlamdasが処理されると、このオブジェクトは自動的に削除されます。
私はこのメソッドが他のコードにいくつかの制限を課しているので、このメソッドが嫌いです。 WinRTの場合、このメソッドはどのスレッドがこのオブジェクトを削除するかを制御しません。その結果、UIスレッドエラーが発生する可能性があります。
これはmutexに固有のものではありません。オブジェクトのメンバがまだ使用されているときは、オブジェクトを削除できません。 – MSalters
@MSalters並行処理が難しいです。単一スレッドのコードでは、デストラクタまたはメンバ関数を同時に実行することはできません。また、オブジェクトが不要になったときにオブジェクトが削除されるため、カウントされたオブジェクトやRAIIを使用することで、常に安全な削除を保証できます。循環参照などは例外です。 – legokangpalla