我最近一直在使用std :: mutex,現在正在尋找一個刪除std :: mutex成員的對象的模式/設計指南。當一個對象作爲使用互斥體的公共函數(監視器函數,關鍵部分等)並且當這個對象被刪除時,它可能有線程仍然在等待互斥體。 std :: mutex在被其他線程鎖定時有未定義的行爲被刪除,所以問題就出現了。如何安全刪除成員std :: 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();
}
});
}
嘗試的解決方案: 析構等待互斥所有等待的線程都處理完後完全解鎖。我通過在互斥體外設置一個標誌來實現它,以便方法中的所有線程都正在退出或等待互斥體。然後,我已經鎖定std :: mutex上次在析構函數。鑑於std :: mutex是公平的,析構函數應該在其他等待線程處理後最後解鎖,然後銷燬該對象。
這不起作用,因爲std :: mutex在大多數平臺中不能保證公平。
工作解決方案類型: 將對象實現爲ref類或其他引用計數對象(智能指針)。然後將這個併發方法作爲一個lamda來實現,這個lamda擁有對象的強引用。一旦所有其他持有該對象的對象都被刪除並且所有帶有互斥鎖的lamdas都被處理,該對象將被自動刪除。
我不喜歡這種方法,因爲它對代碼的其餘部分提出了一些限制。對於WinRT,這種方法不能控制哪個線程刪除這個對象,因此UI線程可能發生錯誤。
這不是特定於互斥體的。當任何成員仍在使用中時,您無法刪除該對象。 – MSalters
@MSalters併發性更難。對於單個線程代碼,您不能同時運行析構函數或成員函數。而且,通過使用ref計數對象或RAII,您始終可以保證安全刪除,因爲只有在不再需要對象時纔會刪除該對象...除了循環引用等外 – legokangpalla