销毁全局对象[关闭]

Posted

技术标签:

【中文标题】销毁全局对象[关闭]【英文标题】:Destroying a global object [closed] 【发布时间】:2017-03-28 07:11:13 【问题描述】:

我有一个由不同线程共享的全局对象。为了提供同步,我在全局对象中添加了一个互斥锁。 在访问对象内部的数据之前,互斥锁会被线程锁定。 一切都很好,除了删除。 如果一个线程正在锁定互斥锁并删除对象。 怎么又能解锁呢? (因为内存将被释放用于数据和互斥锁)

如何使用这种方法实现安全删除,即将互斥体保持在对象内?

【问题讨论】:

如果对象是全局的,为什么需要“销毁”它?为什么不干脆让它在程序退出时被破坏呢? 我同意:当它的生命周期对于应用程序的生命周期而言不是“全局的”时,拥有一个 GLOBAL 对象的意义何在?! 如果您在应用程序的整个生命周期内需要不同的实例,那么继续 @Someprogrammerdude 的评论,那么对象 不应该是全局的. 这是我在描述问题时的错误。通过全局数据,我不是指全局变量。我的意思是堆上的任何对象。 @ChandanSrivastava 让我们了解提供少量示例代码来说明您的问题的重要性。 【参考方案1】:

通常,您有一个这样的全局对象(以std::mutex 为例):

std::mutex theGlobalMutex; // no pointer, no reference!

这样,对象将在程序开始运行之前被初始化,并且在您离开程序时会自动清理(标准保证调用析构函数)。完全没有问题 - 起初。在某些情况下,实际初始化可能会延迟(例如,请参阅文章中间某处提到的 here),但如果您在包含 main 函数的文件中定义全局对象,则应该避免这种情况。

替代方案,如果您真的想自己控制对象创建

std::unique_ptr<std::mutex> the_mutex;

int main()

    // before any theread is created:
    the_mutex = new std::mutex();
    // ...
    return 0;

同样,互斥量将被自动清理,这次是通过智能指针。我假设你知道你应该永远不要更改智能指针中包含的对象,否则你会破坏对竞争条件的保护。

最后一点:

[...],我在全局对象中添加了一个互斥锁。

好的,您的互斥锁是全局对象的一部分。如果要保持线程安全,那么全局对象现在必须在程序的整个生命周期内都存在(或者至少只要有多个线程在运行)。如果您无法通过程序设计来保证这一点 - 那么您需要将互斥体 移出类!所以要么像上面那样有一个单独的互斥锁,要么让互斥锁成为你的类的 static 成员。后一个选项再次像前一个一样提供自动清理。

编辑:

根据您的评论,您想要实现的是保护较大树的较小部分免受竞争条件的影响,以便节点可以独立使用,提供更小的锁定范围/持续时间。

使用您计划的方法,一旦您尝试修改整棵树,就会遇到麻烦:假设您要删除线程 A 中的一个节点。A 获得互斥体,但随后被中断。另一个线程 B 也尝试锁定互斥体,以修改相关对象,但未能这样做并且必须等待。 A 现在删除对象,B 从现在开始对无效数据进行操作!

所以在修改时,你需要保护整棵树!如果您使用最新的 C++ 标准,则可以使用全局/静态 std::shared_mutex 来保护您的树:对节点的每次读取访问都使用对整个树的 shared_lock 进行保护,每次写入访问(添加或删除节点)使用普通锁。

否则,boost 会提供类似的功能,您可以在 *** 上找到解决方案(例如 here 或 here)。

【讨论】:

我不能将其设为静态,因为它可能很多。您可以将其视为树的节点。动态添加和删除节点的位置。 Ann 我想单独同步对这些节点的访问。 我明白了 - 相应地编辑了我的答案。 感谢阿空加瓜的回复。 感谢阿空加瓜的回复。但是解释的解决方案不会给我那么多的并发性。删除节点本身不是我的问题。在树级别上,我正在使用另一个互斥锁来修改(添加/删除)一个节点。因此,该节点将首先从树中删除,然后将被删除。我要保护的是,在删除该节点时,没有人在访问该节点。我认为,这可以通过在外部存储互斥体并将其映射到节点而不是将其存储在节点内来实现。您对此有何看法? @ChandanSrivastava 您对树结构中的并发性的担忧是一个完全不同的问题。您在原始问题中 zero 提到了树。我建议您提出一个新问题,并花更多的精力来解释您的问题。例如。为什么要在节点上进行多线程访问?了解原因有助于了解可能解决方案的限制条件。锁定可能不是正确的方法。 请记住,糟糕的多线程通常比没有多线程更糟糕

以上是关于销毁全局对象[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中全局对象销毁和 atexit 之间的顺序

JavaScript基础知识六(内存释放作用域销毁)

java中静态成员变量、实例变量、局部变量何时创建、何时销毁?

JSJavaScript中的执行环境与作用域

js的内存释放初步理解

如何销毁js的变量