gpt4 book ai didi

C++:并发和析构函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:20:43 44 4
gpt4 key购买 nike

假设您有一个可以被多个线程访问的对象。临界区用于保护敏感区域。但是析构函数呢?即使我一进入析构函数就进入临界区,一旦调用了析构函数,对象就已经失效了吗?

我的思路:假设我进入析构函数,我必须在临界区等待,因为其他线程仍在使用它。一旦他完成,我就可以完成销毁该对象。这有意义吗?

最佳答案

一般来说,你不应该销毁一个对象,直到你知道没有其他线程正在使用它。期间。

根据您的“思路”考虑这种情况:

  • 线程 A:获取对象 X 引用
  • 线程A:锁定对象X
  • 线程 B:获取对象 X 引用
  • 线程 B:在对象 X 锁上阻塞
  • 线程 A:解锁对象 X
  • 线程B:锁定对象X;解锁对象 X;销毁对象X

现在考虑如果时间略有不同会发生什么:

  • 线程 A:获取对象 X 引用
  • 线程 B:获取对象 X 引用
  • 线程B:锁定对象X;解锁对象 X;销毁对象X
  • 线程 A:锁定对象 X - 崩溃

简而言之,对象销毁必须在对象本身以外的某个地方同步。一种常见的选择是使用引用计数。线程 A 将锁定对象引用本身,以防止引用被删除和对象被销毁,直到它设法增加引用计数(使对象保持事件状态)。然后线程 B 只是清除引用并减少引用计数。您无法预测哪个线程将实际调用析构函数,但无论哪种方式都是安全的。

使用boost::shared_ptr 可以很容易地实现引用计数模型。或 std::shared_ptr ;除非所有线程中的所有 shared_ptr 都被销毁(或指向其他地方),否则析构函数不会运行,因此在销毁的那一刻,您知道唯一指向剩余对象的指针是 this 析构函数本身的指针。

请注意,在使用 shared_ptr 时,重要的是要防止原始对象引用发生更改,直到您可以捕获它的拷贝。例如:

std::shared_ptr<SomeObject> objref;
Mutex objlock;

void ok1() {
objlock.lock();
objref->dosomething(); // ok; reference is locked
objlock.unlock();
}

void ok2() {
std::shared_ptr<SomeObject> localref;
objlock.lock();
localref = objref;
objlock.unlock();

localref->dosomething(); // ok; local reference
}

void notok1() {
objref->dosomething(); // not ok; reference may be modified
}

void notok2() {
std::shared_ptr<SomeObject> localref = objref; // not ok; objref may be modified
localref->dosomething();
}

请注意,shared_ptr 上的同时读取 是安全的,因此如果对您的应用程序有意义,您可以选择使用读写锁。

关于C++:并发和析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6710129/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com