在使用互斥锁后,是否需要调用pthread_mutex_destroy来销毁互斥锁?

18

我在C++程序中使用pthread_mutex_t,如下所示:

class Mutex : public noncopyable
{
public:
    Mutex()
    {
        pthread_mutex_init(&m_mutex, NULL);
    }

    void acquire()
    {
        pthread_mutex_lock(&m_mutex);
    }

    void release()
    {
        pthread_mutex_unlock(&m_mutex);
    }

private:
    pthread_mutex_t m_mutex;
};

(该类不可复制 - http://www.boost.org/doc/libs/1_53_0/boost/noncopyable.hpp)

我不理解的问题是,在析构函数中不调用pthread_mutex_destroy是否被认为是错误的?我阅读过的文档没有说明必须调用destroy。

有人知道pthread_mutex_destroy实际上是做什么的以及在什么条件下需要使用吗?

编辑

pthread_mutex_destroy的答案是否也适用于pthread_cond_destroy等函数?它们对我来说似乎几乎没有用处,除非pthread_mutex_init等函数正在分配内存(但对我来说,文档并不完全清晰)。

无论如何调用destroy不会对我造成伤害,所以这个问题在很大程度上是学术性的。

在Linux系统上,destroy似乎只将互斥量设置为无效状态:

int
__pthread_mutex_destroy (mutex)
     pthread_mutex_t *mutex;
{
  if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
      && mutex->__data.__nusers != 0)
    return EBUSY;

  /* Set to an invalid value.  */
  mutex->__data.__kind = -1;

  return 0;
}

(来源于glibc-2.14 / nptl / pthread_mutex_destroy.c)。


请注意,这个 Windows 实现需要销毁:ftp://sourceware.org/pub/pthreads-win32/sources/pthreads-w32-2-9-1-release/pthread_mutex_destroy.c,而 这个 http://locklessinc.com/articles/pthreads_on_windows/ 不需要。 - thang
3个回答

20
如果有人给你提供了一个destroy函数,那么在该对象离开作用域之前,你需要将它作为最后一个操作进行调用。在API没有效果的体系结构和实现上,这将被优化掉,但是如果API未来发生更改,需要清理内部状态而你的代码没有调用它,则你的代码将出现内存和/或资源泄漏。
所以简单的答案是:是的,你必须调用这个API - 并且要知道 - 即使API目前什么也不做,因为虽然API本身在未来永远固定,但是在API背后的实现不是。

3
有趣的是,文档确实没有说你需要销毁。http://linux.die.net/man/3/pthread_mutex_init。看起来这是编写者疏忽。 翻译后:Interestingly enough, the documentation doesn't actually state that it's necessary to destroy. It seems like an oversight on the part of the person who wrote it. The link provided is: http://linux.die.net/man/3/pthread_mutex_init. - thang
@WayneUroda:是的,即使在这种情况下,您也需要调用它:“在默认互斥属性适用的情况下,可以使用宏PTHREAD_MUTEX_INITIALIZER来初始化静态分配的互斥锁。其效果应等同于通过将参数attr指定为NULL调用pthread_mutex_init()进行动态初始化,但不执行任何错误检查。”(http://linux.die.net/man/3/pthread_mutex_destroy) - SecurityMatt
2
@thang:pthread_mutex是一个结构体,而不是C++类。它没有C++析构函数。这就是为什么有pthread_mutex_destroy的存在。当你调用pthread_mutex_init并且不调用pthread_mutex_destroy时会发生什么是由实现定义的。在某些平台上,不会发生任何问题。但在其他系统上,可能会导致您的长时间运行的服务器进程崩溃。这就是为什么您不应该编写针对特定实现的程序,而应该编写针对API的程序。API规定,当您完成时调用pthread_mutex_destroy。如果您按照API编写程序,那么您的代码更有可能在实际使用中正常工作。 - SecurityMatt
1
感谢生动的辩论。答案当然是肯定的,因为调用destroy几乎没有任何成本,而避免潜在的问题却十分重要。我想这个问题更多地是出于我的好奇心以及对实际发生的事情的怀疑(我认为destroy实际上什么都不做),但现在我感到非常傻,甚至连问这个问题都觉得有些多余——我只是在文档中没有得到一个直接的回答,所以来这里问。 - Wayne Uroda
1
这整个讨论都很荒谬。摧毁互斥锁的正确而可靠的方法是拔掉系统插头。 - BoltClock
显示剩余24条评论

8
从管理POSIX的标准的IEEE文档中得知:

pthread_mutex_destroy()函数将销毁由mutex引用的互斥对象;互斥对象变成未初始化状态。实现可能会导致pthread_mutex_destroy()将由mutex引用的对象设置为无效值。销毁的互斥对象可以使用pthread_mutex_init()重新初始化;在销毁后引用该对象的结果是未定义的。

文档没有说你必须调用它。但这是一个好习惯。
调用此api将向POSIX库发出信号,释放在初始化期间为该特定互斥对象保留的所有资源。
可以合理地假设互斥初始化确实分配/保留了一些资源。


3
实际上,这个文件甚至没有说这样做是良好的实践 :p 我认为这是撰写该文件的人疏忽了。例如在Windows中,可以使用http://msdn.microsoft.com/en-us/library/windows/desktop/ms682411(v=vs.85).aspx。 使用CloseHandle函数来关闭句柄。当进程终止时,系统会自动关闭句柄。当最后一个句柄被关闭时,互斥体对象将被销毁。 - thang
@thang:嗯,我不确定这是否是一个洞察,但对我来说,这似乎是相当合乎逻辑的做法。如果确实想要严谨并深入研究,那么可以很容易地编写一个小样例程序。在valgrind下运行它,并检查调用该函数和不调用该函数时的系统资源情况。 - Alok Save
你已经阅读了C++标准。看看所有关于事物规范的细节,没有留给想象的余地...为什么这是个例外? - thang
@thang:C和C++标准非常全面,可能是因为大量编译器实现需要遵守这些标准,而IEEE并非如此。这只是一个猜测,我没有权威地断言。此外,我认为“为什么这是一个例外”的确切原因只能由IEEE委员会的成员权威回答。 - Alok Save
1
我怀疑这只是一个小小的疏忽。事实上,正如我在下面提到的,在其他操作系统中(例如至少有一个:http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.genprogc%2Fdoc%2Fgenprogc%2Fmutexes.htm 像任何可以在线程之间共享的系统资源一样,分配在线程堆栈上的互斥量必须在线程终止之前被销毁),他们的文档中明确说明了这一点。 - thang

5
几年过去了,@SecurityMatt是正确的。为了解决争论,您必须调用pthread_mutex_destroy以满足API要求并可能释放内存。
以下是最新版本pthread_mutex_destroy的摘录:
int _pthread_mutex_destroy (pthread_mutex_t *mutex)
{
  if (mutex->__attr == __PTHREAD_ERRORCHECK_MUTEXATTR
      || mutex->__attr == __PTHREAD_RECURSIVE_MUTEXATTR)
    /* Static attributes.  */
    ;
  else
    free (mutex->__attr);

  return 0;
}

2
不,记住pthread mutex有三种类型,PTHREAD_ERRORCHECK和PTHREAD_RECURSIVE由if处理,最后PTHREAD_NORMAL的__attr为空。这意味着所示的_pthread_mutex_destroy实现等同于{}。 - midjji

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接