[英]Why is std::weak_ptr::expired optimized away?
在下面的代码中, while ( !Ref.expired() );
被快乐地优化成无限循环。 如果代码行改为while ( !Ref.lock() );
。 一切都按预期工作。 真的有两个问题:
1)当std::weak_ptr::expired()
访问内存隔离计数器时,编译器如何优化过期?
2) Ref.lock()
实际上是安全的,还是可以将其优化掉?
示例代码如下。
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
class A
{
public:
A()
{
m_SomePtr = std::make_shared<bool>( false );
}
virtual ~A()
{
std::weak_ptr<bool> Ref = m_SomePtr;
m_SomePtr.reset();
// Spin (will be optimised into an infinite loop in release builds)
while ( !Ref.expired() );
}
std::shared_ptr<bool> GetPtr() const { return m_SomePtr; }
private:
std::shared_ptr<bool> m_SomePtr;
};
class B
{
public:
B( std::shared_ptr<bool> SomePtr ) : m_Ref( SomePtr ) {}
void LockPtr() { m_SomePtr = m_Ref.lock(); }
void UnLockPtr() { m_SomePtr.reset(); }
private:
std::shared_ptr<bool> m_SomePtr;
std::weak_ptr<bool> m_Ref;
};
int main()
{
std::unique_ptr<A> a( new A() );
std::unique_ptr<B> b( new B( a->GetPtr() ) );
b->LockPtr();
std::cout << "Starting " << std::endl;
std::thread first( [&]()
{
std::this_thread::sleep_for( std::chrono::seconds( 5 ) );
b->UnLockPtr();
} );
std::thread second( [&]()
{
a.reset( nullptr );
} );
first.join();
second.join();
std::cout << "Complete" << std::endl;
return 0;
}
你的程序不正确; 共享所有权指针工具不用于同步。
[intro.multithread] / 24:
实现可以假设任何线程最终将执行以下操作之一:
- 终止,
- 调用库I / O函数,
- 访问或修改易失性对象,或
- 执行同步操作或原子操作。
std::weak_ptr::expired()
不是同步操作或原子操作; 标准所说的是它没有引入数据竞争。 由于对库缺陷2316的解析, std::weak_ptr::lock()
被认为是原子操作,所以回答2)使用Ref.lock()
代码从C ++ 14开始是有效的。
现在,如果您尝试使用语言和库设施创建自己的weak_ptr
库实现,那么它必然会使用同步和/或原子操作工具,因此用户提供的weak_ptr::expired()
会可以旋转(实现将有义务确保线程最终取得进展,每[intro.multithread] / 2和/ 25)。 但是实现没有义务将自己的库限制为语言和库设施。
我不完全确定编译器如何优化对expired()
的访问。 我猜想MSVC库正在利用编译器/优化器观察到的x86内存模型的各个方面,而不是C ++内存模型所保证的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.