【问题标题】:is it necessary to call pthread_mutex_destroy on a mutex?是否有必要在互斥体上调用 pthread_mutex_destroy?
【发布时间】:2013-01-21 04:31:16
【问题描述】:

我在一个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

我不明白的事情 - not 在析构函数中调用 pthread_mutex_destroy 是否被视为错误?我读过的文档没有说明必须调用destroy。

有谁知道pthread_mutex_destroy实际上是做什么的,在什么条件下需要它?

编辑

pthread_mutex_destroy 的答案是否也适用于pthread_cond_destroy 等?对我来说,它们似乎几乎是无用的功能,除非pthread_mutex_init 等。人。正在分配内存? (对我来说,文档对此并不完全清楚。)

不管怎样,调用破坏并没有伤害我,所以这个问题主要是学术性的。

无论如何,在 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)。

【问题讨论】:

标签: c++ pthreads posix mutex


【解决方案1】:

如果有人为您提供了一个销毁函数,那么您需要在该对象超出范围之前调用它作为对该对象的最终操作。

在 API 没有影响的架构和实现中,这将被优化掉,但是如果 API 将来发生变化以需要清理内部状态并且您的代码没有调用它,您的代码现在将拥有内存并且/或资源泄漏。

所以简单的答案是肯定的;你必须调用这个 API - 事情就是这样 - 即使 API 目前什么都不做,因为虽然 API 本身在未来永远是固定的,但 API 背后的实现却不是。 p>

【讨论】:

  • 实际上,有趣的是,文档确实没有说您需要销毁。 linux.die.net/man/3/pthread_mutex_init。似乎是作者的疏忽。
  • Create/Destroy 是 C 代码中的一种常见模式,大多数开发人员和文档编写者认为,如果他们为您提供了一个“destroy”方法,您必须在调用 init 之后但之前调用它对象超出范围。
  • @thang:pthread_mutex 是一个结构,而不是 C++ 类。它没有 C++ 析构函数。这就是 pthread_mutex_destroy 存在的原因。当您调用 pthread_mutex_init 而不调用 pthread_mutex_destroy 时会发生什么的问题是实现定义的。在某些平台上,不会发生任何不好的事情。在其他系统上,它可能会导致您长时间运行的服务器进程崩溃。这就是为什么您不对实现进行编程的原因。您对 API 进行编程。 API 说你完成后调用 pthread_mutex_destroy。如果您对 API 进行编程,您的代码更有可能实际运行。
  • 感谢热烈的辩论。答案当然是肯定的,因为调用destroy 的成本很低,同时避免了潜在的问题。我想这个问题更多是出于我对实际发生的事情的好奇心(以及我怀疑破坏实际上根本没有做任何事情),但现在我什至觉得问这个问题都很愚蠢——我只是没有得到一个直接的答案文档,所以我来到这里。
  • 整个讨论都是愚蠢的。销毁互斥锁​​的正确且可靠的方法是拔出系统。
【解决方案2】:

来自IEEE documentation,这是管理 POSIX 的标准:

pthread_mutex_destroy() 函数将销毁 mutex 引用的 mutex 对象;互斥对象实际上变得未初始化。实现可能会导致 pthread_mutex_destroy() 将 mutex 引用的对象设置为无效值。可以使用 pthread_mutex_init() 重新初始化被破坏的互斥对象;在对象被销毁后以其他方式引用该对象的结果是未定义的。

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

【讨论】:

  • 实际上该文档甚至没有说这样做是一种好习惯:p 我认为这是对编写它的人的疏忽。例如,在 Windows 中,msdn.microsoft.com/en-us/library/windows/desktop/…使用 CloseHandle 函数关闭句柄。当进程终止时,系统会自动关闭句柄。互斥对象在其最后一个句柄关闭时被销毁。
  • @thang:嗯,我不确定这是否是一种洞察力,但对我来说,这样做似乎很合乎逻辑。如果真的想学究气,深入研究,那么编写一个小示例程序很容易。在 valgrind 下运行它,并在调用函数和不调用函数的情况下检查系统资源。
  • 您已经阅读了 c++ 标准。查看有关指定事物方式的所有细节。没有什么可以想象的......为什么这是一个例外?
  • @thang:C 和 C++ 标准非常全面,这可能是因为大量编译器实现需要遵守它们,而 IEEE 则不然。这只是一个猜测。我无权坚定地主张这一点。此外,我认为为什么这是一个例外的确切推理只能由 IEEE 委员会中的某个人来权威地回答。
  • 我怀疑这只是一个小小的疏忽。事实上,正如我在下面提到的,在其他操作系统中(呃。至少另一个:pic.dhe.ibm.com/infocenter/aix/v7r1/… 就像任何可以在线程之间共享的系统资源一样,分配在线程堆栈上的互斥锁必须在线程被销毁之前终止) 实际上确实在他们的文档中明确说明了这一点。
【解决方案3】:

几年过去了,@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;
}

【讨论】:

    猜你喜欢
    • 2023-03-30
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2015-07-20
    • 2010-09-12
    • 2011-01-20
    • 2017-10-23
    相关资源
    最近更新 更多