2009-12-15 4 views
9

Я знаю, что название моего сообщения может показаться провокационным, поскольку boost :: mutex специально не раскрывает блокировку/разблокировку (во избежание мертвых замки).boost :: mutex/Как проверить, заблокирован ли мьютекс

Однако документация по ускорению довольно короткая по этим аспектам (по меньшей мере), поэтому я спрашиваю, может ли кто-нибудь помочь мне в следующем прецеденте.

Предположим, у вас есть класс Foo, который имеет:
- деструктор, который занимает некоторое время, чтобы завершить
- метод, который вызывается отдельной нитью, но не должен быть вызван во время уничтожения

class Foo 
{ 
public: 

    virtual ~Foo() 
    { 
    //Time consuming operations here 
    } 


    //Method called by a timer belonging to a distinct class 
    void OnTimer() 
    { 
    //Other time consuming stuff. Should not be called during destruction ! 
    } 


}; 

Я пытался (без успеха) осуществлять версию на основе повышения :: мьютекс

//boost::mutex implementation 
class Foo 
{ 
public: 
    Foo() 
    { 
    } 

    virtual ~Foo() 
    { 
    { 
     boost::mutex::scoped_lock lock(mDisposingMutex); 
     //Time consuming operations here 
    } 
    } 


    //Method called by a timer belonging to a distinct class 
    void OnTimer() 
    { 
    { 
     //Imaginary code here: mutex::locked() method is private !!! 
     if (! mDisposingMutex.locked()) 
     return; 
    }  
    //Other time consuming stuff. Should not be called during destruction ! 
    } 

private: 
    boost::mutex mDisposingMutex; 
}; 

Am Я совершенно неправильно? Может ли кто-нибудь сказать мне, как это должно быть сделано с boost :: mutex?

Спасибо!

+0

Почему ваш объект быть разрушен, а другой поток еще есть указатель на него? –

+0

Не отвечая на вопрос напрямую, можете ли вы отменить регистрацию, провоцируя вызов OnTimer() как первый шаг в вашем деструкторе? Разумеется, вызов все равно может происходить асинхронно «в одно и то же время», но пока неясно, почему этот объект, подвергающийся разрушению, по-прежнему является целью этих обратных вызовов. – seh

+0

@Anon: Согласен, это запах кода. Я все еще интересуюсь ответом. @Seh: Ваш комментарий опирается на тот же код. Однако я не могу отменить его напрямую, не нарушая инкапсуляцию. –

ответ

5

Если вы обязуетесь использовать Lockable::lock() в теле деструктора, вы могли бы иметь свою OnTimer() функцию использовать Lockable::try_lock(), и исходить только если эта функция возвращает истину. То, что будет OnTimer(), положит деструктор на удержание, если сначала начинается OnTimer(), но оно все еще не решает проблему запуска, завершения и освобождения мьютекса деструктора, а затем OnTimer(), начиная и успешно захватывая мьютексы.

Такая последовательность, скорее всего, относится к сфере неопределенного поведения, но это проклятие не остановит ее. Использование флага состояния в дополнение к мьютексу - аналогично тому, что я описал в моем комментарии выше, может позволить вам обнаружить этот последний случай и остановить OnTimer() от выполнения чего-либо, кроме чтения флага. Однако в какой-то момент это просто помещает Band-Aids поверх Band-Aids.

2

мьютекс :: try_lock()

+0

Это возвращает false, если вы тот, кто заблокировал мьютекс. –

4

@Seh: Я полностью согласен, что это запах кода, и я должен (и будет) исправлять основную причину.

Однако, в надежде помочь любому, кто столкнулся бы с той же проблемой, что и я (например, сражаясь с документом boost), я попытался реализовать ваше предложение. ниже код Теперь компилирует правильно (хотя код запах теперь очень сильный)

#include <boost/thread/mutex.hpp> 

//boost::mutex implementation 
class Foo 
{ 
public: 
    Foo() : 
    mIsDisposing(false) 
    { 
    } 

    virtual ~Foo() 
    { 
    { 
     boost::try_mutex::scoped_try_lock lock(mDisposingMutex); 
     if (! lock.locked()) 
     { 
     //Die by horrible death, or wait before trying again... 
     } 
     else 
     { 
     mIsDisposing = true; 
     } 
     //Time consuming operations here 
    } 

    } 


    //Method called by a timer belonging to a distinct class 
    void OnTimer() 
    { 
    { 
     boost::try_mutex::scoped_try_lock lock(mDisposingMutex); 
     if (! lock.locked() || mIsDisposing) 
     { 
     return;  
     } 
    }  
    //Other time consuming stuff. Should not be called during destruction ! 
    } 

private: 
    boost::try_mutex mDisposingMutex; 
    bool mIsDisposing; 
}; 
Смежные вопросы