2

はじめに:このエラーの発生に関する多くの投稿を読みました (例: boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed )。

さらに、これらの投稿でよく提案されているように、RAII を使用できません。

さらに、このエラーは発生しないため、「最小限のコンパイル例」を示すことはできません。

私の問題: FIFO リストを表すクラスに 2 つのミューテックスがあります。これらのミューテックスは、アンカー ポインターとバック ポインターをロックするために使用されます。

クラスが破棄された時点で、 が破棄されたback_mutex後で の破棄は失敗しますanchor_mutex。これはエラーメッセージです:

boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed.

POSIX-Specpthread_mutex_destroyによると、失敗するのはEINVAL、mutex が無効なEBUSY場合と、mutex がロックまたは参照されている場合の 2 つのみです。

その知識のために、テストのためにデストラクタを次のように変更しました。

template<class T>
Fifo_Emut<T>::~Fifo_Emut()
{
   this->clear();
   anchor_mutex.lock();
   back_mutex.lock();
   anchor_mutex.unlock();
   back_mutex.unlock();
}

それにもかかわらず、エラーは依然として同じ位置にあります。EINVAL2 つのケースのいずれかEBUSYが関連している場合、mutex のロックとロック解除は失敗するはずです。また、デストラクタを呼び出すスレッドが、他のすべてのスレッドが以前に参加した最後の生きているスレッドであることを保証できます。

追加のテストとして、push_back と pop_front の最初の行に return を書きましたが、エラーは発生しません。push_back のみを使用した場合にも発生します

「一種の」完全性のために、push_back および pop_front メソッドでミューテックスを使用するコード:

/**
 * @brief      appends a new list element to the back end of the list
 * @param[in]  data     the data to be copied into the list_element
 **/
template<class T>
void Fifo_Emut<T>::push_back(const T const& data)
{
   back_mutex.lock();
   if(back == NULL)
   {
      if(!anchor_mutex.try_lock())
      {
         //if we cannot aquire anchor_mutex we have to release back_mutex and try again to avoid a deadlock
         back_mutex.unlock();
         return this->push_back(data);
      }
      if(anchor == NULL)
      {
         MutexListElement<T>* tmp;
         tmp = new MutexListElement<T>(data);
         anchor = tmp;
         back = tmp;
         boost::interprocess::ipcdetail::atomic_write32(&number_of_elements, 1);
         anchor_mutex.unlock();
         back_mutex.unlock();
      }
      //else error normally handled
   }
   else
   {
      MutexListElement<T>* tmp;
      back->lock();
      tmp = new MutexListElement<T>(back, data);
      boost::interprocess::ipcdetail::atomic_inc32(&number_of_elements);
      back->unlock();
      back = tmp;
      back_mutex.unlock();
   }
}

/**
 * @brief      erases the first element of the queue
 * @returns    a copy of the data held in the erased element
 **/
template<class T>
T Fifo_Emut<T>::pop_front(void)
{
   uint32_t elements = boost::interprocess::ipcdetail::atomic_read32(&number_of_elements);
   if(elements == 0)
   {
      return NULL;
   }
   if(elements == 1)
   {
      anchor_mutex.lock();
      back_mutex.lock();
      if(elements == boost::interprocess::ipcdetail::atomic_read32(&number_of_elements))
      {
         //still the same so we can pop
         MutexListElement<T>* erase = anchor;
         erase->lock(); //we do not have to lock next since tis is the only one
         anchor = NULL;
         back = NULL;
         boost::interprocess::ipcdetail::atomic_write32(&number_of_elements, 0);
         anchor_mutex.unlock();
         back_mutex.unlock();
         T tmp = erase->getData();
         erase->unlock();
         delete erase;
         return tmp;
      }
      else
      {
         //something has changed so we have to try again
         back_mutex.unlock();
         anchor_mutex.unlock();
         return this->pop_front();
      }
   }
   else
   {
      anchor_mutex.lock();
      if(boost::interprocess::ipcdetail::atomic_read32(&number_of_elements) > 1)
      {
         //still more than one element in the queue so we can just pop whitout changing back pointer
         MutexListElement<T>* erase = anchor;
         erase->lock();
         (dynamic_cast<MutexListElement<T>*>(anchor->next))->lock();
         anchor = dynamic_cast<MutexListElement<T>*>(anchor->next);
         anchor->prev = NULL;
         boost::interprocess::ipcdetail::atomic_dec32(&number_of_elements);
         anchor->unlock();
         anchor_mutex.unlock();
         T tmp = erase->getData();
         erase->unlock();
         delete erase;
         return tmp;
     }
     else
     {
        //number of elements decreased to other case during locking
        anchor_mutex.unlock();
        return this->pop_front();
     }
   }
}

質問: 「機能している」mutex の破棄に失敗する可能性はありますか? それとも私はここで何かを監督していますか?どうすればそのエラーを取り除くことができますか? コードと仮定のどこが間違っていますか?

4

0 に答える 0