はじめに:このエラーの発生に関する多くの投稿を読みました (例: 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();
}
それにもかかわらず、エラーは依然として同じ位置にあります。EINVAL
2 つのケースのいずれか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 の破棄に失敗する可能性はありますか? それとも私はここで何かを監督していますか?どうすればそのエラーを取り除くことができますか? コードと仮定のどこが間違っていますか?