首先:我已经阅读了许多关于此错误发生的帖子(例如boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed),我可以看到它们不适用于我的情况。
此外,我不能像那些帖子中经常建议的那样使用 RAII。
此外,我不能给出“最小编译示例”,因为那里不会发生此错误。
我的问题: 我在一个代表 FIFO 列表的类中有两个互斥锁,互斥锁用于锁定锚指针和反向指针。
在那一刻,当类被破坏时,在已经被破坏back_mutex
之后的破坏失败anchor_mutex
。这是错误信息:
boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed.
POSIX-Specpthread_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的第一行写了一个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();
}
}
}
问题: “正常工作”的互斥锁怎么可能在被破坏时失败?还是我在这里监督一些事情?我怎样才能摆脱这个错误?我在代码和假设中做错了什么?