shared_ptr的删除程序是否执行任何同步?
Does shared_ptr's deleter do any synchronization?
每个使用多线程环境的人都知道,您必须在线程之间同步以避免竞争情况。 我对shared_ptr删除器中发生的同步特别感兴趣。
在我的真实情况下,我有多个类交互,其中一些类知道同步正在进行,而另一些则不知道。 在这个例子中,我人为地将它们全部捆绑到一个对象上来阐明这个问题:
class TestObject
{
public:
TestObject()
: mMarked(false)
{ }
~TestObject()
{
// use of mMarked here indicates that the destructor must be synchronized
// with any thread that calls mark()
std::cout << "Object " << (mMarked ? "was marked." : "was not marked.");
}
void mark() { mMarked = true; }
void someBehaviorThatDoesntNeedSynchronization();
private:
bool mMarked;
};
thread 1:
std::shared_ptr<TestObject> objPtr1 = /* initialize to some instance */;
objPtr1->someBehaviorThatDoesntNeedSynchronization();
objPtr1.reset(); // may call the destructor
thread 2:
std::shared_ptr<TestObject> objPtr2 = /* initialize to the same instance */;
objPtr2->mark();
objPtr2.reset(); // may call the destructor
该规范似乎表明根本没有同步。 然而,这似乎很不体贴。 似乎线程 1 应该知道对象发生的所有同步,然后才能拥有调用析构函数的权限(如果在堆栈展开期间调用析构函数,这可能会很残酷(。
我错过了什么吗? 我知道shared_ptr的每个实现实际上都出于这个原因进行了同步,但我在规范中找不到任何内容来表明我可以信任它。
规范中是否有任何内容表明在调用删除程序之前将进行同步?
从参考:
所有成员函数(包括复制构造函数和复制赋值(都可以由不同shared_ptr实例上的多个线程调用,而无需额外的同步,即使这些实例是副本并共享同一对象的所有权也是如此。如果多个执行线程在不同步的情况下访问同一shared_ptr,并且其中任何一个访问使用 shared_ptr 的非常量成员函数,则会发生数据争用,原子函数的shared_ptr重载可用于防止数据争用。
所以std::shared_ptr
的同步有限。 不能使用非const
方法(包括析构函数(在多个线程中安全地访问shared_ptr
的单个实例。
但是,两个共享相同生存期且数据shared_ptr
都可以安全地从不同的线程访问。
如何实现这一点的一个想法是,销毁会进行互锁递减,这会减少引用计数器并返回它以原子方式减少的值。
然后,无论哪个~shared_ptr
(或.reset()
(将其减少到0
删除对象。
如果我们假设objPtr1
和objPtr2
从同一源正确构造(可能具有同步,或者在传递给工人之前在同一线程中(,并且当.reset()
被称为时,除了这两个之外的所有其他shared_ptr
都超出了范围,那么两个.reset()
中的一个将破坏TestObject
。
现在,从技术上讲,mMarked
的值是不同步的,并且当一个线程在另一个线程(可能(读取它之前以不同步的方式修改该值时,结果是未定义的行为。 这方面的一个实际示例是mMarked
由两个 CPU 单独缓存。 在一种情况下,缓存的副本将被修改。 这与其他缓存不同步,然后后者碰巧在.reset()
上销毁。
因此,简而言之,在多个线程中访问引用同一对象本身的不同shared_ptr
是安全的,但对共享对象的访问不会同步。
当shared_ptr对象释放其在指针上的保留时,它会以原子方式递减引用计数。如果该引用计数现在为零,则发布shared_ptr是引用该对象的唯一实例,它调用删除程序。
因此,具有共享所有权的对象销毁由引用计数的原子操作同步。
- 我在执行任何程序时被拒绝在 devcpp 中访问
- 不执行任何操作的函数调用C++
- 如果普通默认构造函数不执行任何操作,为什么我们不能使用 malloc 创建平凡可构造的对象?
- GDI+-无法对Gdiplus::Graphics(C++)执行任何操作
- 当我将 DLL 注入现有进程时,DLLMain 不执行任何操作
- 调用函数来创建 WinAPI 按钮不会执行任何操作
- 发送到另一个窗口的鼠标移动消息不执行任何操作
- 如果默认构造函数不执行任何操作,则目的是什么
- 尝试执行任何需要它的操作时,无法修复 WinAPI 中的"invalid handle"错误
- 程序在运行时不执行任何操作
- 调用向量内的函数指针不执行任何操作
- getch() 函数在输入 key 时不执行任何操作
- 在集合上运行的函数模板,该集合具有默认的"transform"函数,该函数不执行任何操作
- 重复Handle()是否执行任何解释性通信(IPC),如果不是为什么目标参数
- 基于 Visual Studio c++ 的 exe 不执行任何操作
- C/C++ 套接字:如果我在 IPv6 TCP 连接之前执行任何操作,则连接将失败
- 在执行任何程序代码之前,通过静态 .lib 链接到 dll 的程序会发生什么情况
- 使用 for 循环反转数组不执行任何操作
- C++功能运算符结构不执行任何操作
- 如何创建不执行任何操作的 #define