繁体   English   中英

`std :: shared_ptr`原子与`reset()`的复制构造函数是什么?

[英]Is the copy constructor of `std::shared_ptr` atomic versus `reset()`?

这是一个验证问题,以确保我获得正确的语言律师欢迎的细节。

我想知道我可以在下面的代码中使用std::shared_ptr ,而不需要用atomic_shared_ptr重写它。 的示例进行了简化,但本质上的单个实例内的可能的竞争条件example (* 1)的拷贝构造之间shared_ptr和(* 2)的调用reset()

请注意, p的普通指针在此处不起作用。 如果p在测试和调用some_predicate之间变为null,那么你将间接一个空指针。 这就是首先使用shared_ptr的原因。 我想确保我实际上是在解决竞争条件,而不是简单地将其移到其他地方。

(这不是问题的关键,但是这个代码乍一看似乎是错误的T的行为是幂等的。一旦p完成它的工作,它就不再需要了。)

template< class T >
class example
{
    shared_ptr< T > p ;
public:
    example()
        : p( make_shared( T() ) )
    {}
    void f()
    {
        shared_ptr< T > p_transient(p) ; // *1
        if ( p_transient && p_transient -> some_predicate() )
        {
            p.reset() ; // *2
        }
    }
};

假设(* 1)和(* 2)同时执行。 我可以想到比赛的两个可能的结果。 (在这两种情况下,代码都是正确的。)我的问题是这些是否是唯一的情况:

  • 复制在reset之前生效,因此p_transient使T的成员实例保持活动状态。 f返回时,删除器在线程* 1中运行。 T的幂等在这里发挥作用。)
  • reset在复制之前生效,因此p_transient初始化为空。 reset返回之前,删除程序在线程* 2中运行。

我无法摆脱这种感觉,我在这里得到了一些东西,所以我决定写下这个问题。 我缺少什么?


PS这就是我所缺少的。 shared_ptr并不特别。 不知怎的,我认为这可能是因为我之前已经实现了智能指针(太多)。 共享指针,特别是当指针也有弱指针时,几乎需要对其(隐藏)共享状态进行互斥保护。 我认为保护必须包含整个对象,但事实并非如此。

感谢响应者对标准的参考。 数据竞争导致未定义行为的一般规则是1.10 / 27“多线程执行和数据竞争[intro.multithread]”。 特别是,这意味着在这种情况下可能会违反后置条件。

为了让#1和#2同时执行,那么你必须在两个不同的线程中调用example::f 如果这些是在不同的example实例上,那么example::p也可能是不同的实例,所以没有问题。

如果这些是在同一个 example实例上,那么您违反了有关标准库竞争条件的C ++一般规则。 如果您访问不同的对象实例,您(通常)只能保证不受竞争条件的影响。 所以你可以在两个不同的线程中push_back两个不同的vector ,但不是相同的 vector

shared_ptr提供同样的保证。 只要您不尝试从两个不同的线程访问相同的shared_ptr实例,就可以了。 一旦你这样做,所有的赌注都会被取消。

原子shared_ptr函数适用于您希望从不同线程原子操作同一对象的情况。

例如:

shared_ptr< T > p_transient(atomic_load(&p));
if ( p_transient && p_transient -> some_predicate() )
{
    atomic_store(&p, shared_ptr<T>());
}

或者,您可以将f包装在互斥锁或某些内容中。 这也意味着您不必使用shared_ptr ,因为您的可能破坏也包含在互斥锁中。

你所看到的被称为数据竞赛。 每当一个线程可以写入某些数据而另一个线程可能读取或写入该数据时,它就被称为数据争用。

数据争用是未定义的行为 这意味着可能发生的事情没有限制。 我发誓博客条目良性竞赛案例:可能出现什么问题? 对于这些事情。 他列出了一些可能出错的事情。

一个例子是,如果写入内存位置,实际上允许编译器使用此内存空间来保存溢出寄存器。 它不会经常发生,但它可能发生。 上面提到的博客显示了一个极端的例子,这种形式的数据竞赛无意中发射了核导弹! (这里希望真正的核导弹发射计算机更加强大!)

如果要让两个线程与一段数据交互,则必须防止数据争用。 这通常用互斥或原子来完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM