要开始:我已阅读很多关于此错误发生的帖子(例如boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed),而我可以看到它们不适用于我的情况。
此外,我不能像这些帖子中经常建议的那样使用RAII。
我还不能给出“最小编译示例”,因为此处不会出现此错误。
我的问题: 我在一个表示FIFO-List的类中有两个互斥锁,互斥锁用于锁定锚指针和后指针。
在类被销毁的那一刻,back_mutex
的破坏在anchor_mutex
已被破坏后失败。这是错误消息:
boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed.
POSIX-Spec表示pthread_mutex_destroy
失败的唯一两种情况是EINVAL
,如果互斥锁无效,EBUSY
,如果互斥锁被锁定或引用。
由于这些知识,我将我的析构函数更改为以下内容进行测试:
template<class T>
Fifo_Emut<T>::~Fifo_Emut()
{
this->clear();
anchor_mutex.lock();
back_mutex.lock();
anchor_mutex.unlock();
back_mutex.unlock();
}
尽管错误仍然存在于同一位置。
正如我所建议的,如果EINVAL
或EBUSY
这两种情况中的一种相关,则互斥锁的锁定和解锁应该会失败。此外,我可以保证调用析构函数的线程是所有其他人之前加入的最后一个生成线程。
作为一个额外的测试,我在push_back和pop_front的第一行写了一个返回,然后就不会发生错误。仅使用push_back
时也会发生这种情况对于'类型'完整性,在push_back和pop_front mehtods中使用互斥锁的代码:
/**
* @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();
}
}
}
问题: “正常运行”的互斥锁如何被破坏失败? 或者我在这里监督一些事情?我该如何摆脱这个错误?我在代码和假设中犯了什么错误?