初始化原子指针是原子的吗?如果初始化或内存分配引发,会发生什么情况?

Is initializing a atomic pointer atomic? What happens if initialization or memory allocation throws?

本文关键字:初始化 分配 什么情况 内存 如果 指针 原子的      更新时间:2023-10-16

如果我一次性声明并定义一个原子指针,就像 -

std::atomic<int*> iptr = new int(1);    
std::atomic<T*> iptr = new T();

据我了解,整个操作不是原子的。

new T(( 涉及分配内存,构造 T 对象,然后将其原子分配给 iptr。T 可能是平凡可构造的,在这种情况下,构造 T 不应该抛出,但一些用户定义的 T 可能会抛出。

如果在 T 构造或内存分配之间,其他线程使用 iptr 怎么办?

这个操作真的是原子的吗?使它原子化的一种方法是打破声明和定义,例如

T* temp = new T();
std::atomic<T*> iptr = temp;    

有没有其他方法可以在原子上做同样的事情? 我的理解有缺陷吗?

new T()涉及分配内存,

是的。

构造T对象

是的。

然后它将以原子方式分配给 IPTR。

确切地说(几乎,它是此处使用的对象的地址(。它用于内存分配和构造完成后初始化原子。

T可能是微不足道的可构造的,在这种情况下,构造T不应该抛出,但一些用户定义的T可能会抛出。

如果是这样,则不会达到原子的初始化。如果 c'tor 抛出,new表达式不会泄漏内存,它会调用正确的去allcoation函数。因此,您的临时表达式和直接使用新表达式具有完全相同的语义。

新的未命名对象的创建不是原子的,但不需要原子的。[如上所述,任何异常只会影响在分配给原子之前创建的临时对象的生存期,并且应该清理得很好。

将该临时指针分配给原子指针是原子指针的。

我最大的担忧是,就目前而言,您的代码无法检测到另一个线程是否完成了分配,因此您必须考虑使用 testandset 或 swap。然后你就会遇到测试/交换失败的麻烦,并且你有一个指向你不再需要的对象的临时指针。

如果您使用局部变量(而不是未命名的临时变量(,则有机会对其进行清理。

如果你对原子和临时使用智能指针,它将自毁。

但是,在许多情况下,除非确实需要临时对象,否则最好不要创建临时对象,但这意味着在整个创建过程中具有互斥锁,但是您可以在输入互斥锁之前进行轻量级检查。这更像是单例静态变量的作用。如果要创建单例,则没有真正的缺点,因为其他线程无论如何都必须等待。