jeudi 1 septembre 2016

How to safely delete member std::mutex?

I've been using std::mutex lately and is now looking for a pattern/design guide on deleting an object that has std::mutex as member. The problem arises when an object as a public function that uses the mutex(monitor function, critical section, etc) and when this object is deleted, it might have threads still waiting on the mutex. std::mutex have undefined behavior deleted while being locked by other thread, and so the problem arises.

I want to know what is a generally acceptable pattern to use in this case. Or if this is considered a bad coding style, a way to avoid this design, ie) do not delete an object whose mutex methods are still being waited on.

Example:

//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();
        }        
    });
}

Tried solutions: Destructor waiting for mutex to completely unlock after all waiting threads are processed. I've implemented it by setting a flag outside of mutex, so that all threads in the method are either exiting or waiting on the mutex. Then I've locked the std::mutex for last time at destructor. Given that the std::mutex is fair, destructor should be unlocked last after other waiting threads are processed, then destroy the object.

This doesn't work because std::mutex does not guarantee fairness in most platforms.

Sort of working solution: Implement the object as a ref class or other reference counted object(smart pointers). Then implement the concurrent method as a lamda that holds a strong reference to the object. Once all other objects holding this object are deleted and all lamdas with mutexes are processed, this object will be deleted automatically.

I don't like this method as it poses some restriction on the rest of the code. For WinRT, this method does not give control which thread deletes this object, as a result, UI thread error can occur.

Aucun commentaire:

Enregistrer un commentaire