boost :: mutex / Как проверить, заблокирован ли мьютекс - PullRequest
9 голосов
/ 15 декабря 2009

Я знаю, я знаю, название моего сообщения может показаться провокационным, так как 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

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

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

Спасибо!

Ответы [ 3 ]

6 голосов
/ 15 декабря 2009

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

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

4 голосов
/ 15 декабря 2009

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

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

#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;
};
2 голосов
/ 15 декабря 2009

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

...