[英]Is assignment in automatic reference counting systems thread-safe?
Swift,Vala和C ++之类的语言(通过shared_ptr)通过引用计数来管理内存。 据我所知,这些系统中对引用计数的更新是原子执行的,因此是线程安全的。
但是,每次重新分配引用/指针时,先前引用的对象需要引用计数递减,新引用的对象需要引用增量,最后必须重新分配引用本身。 因此,如果可以从多个线程访问同一引用(即通过全局变量),并且同时由多个线程重新分配该引用,则引用计数可能会出现乱码。
那么C ++共享指针,Vala引用,Swift引用是否采取了步骤来避免此类问题? 如果不是,则三种语言中的每种语言都需要采取什么步骤来确保这种访问的安全性?
任何见解都表示赞赏。 谢谢!
请参阅http://en.cppreference.com/w/cpp/memory/shared_ptr的最后一段
多个线程可以在shared_ptr的不同实例上调用所有成员函数(包括副本构造函数和副本分配),而无需额外同步,即使这些实例是副本并共享同一对象的所有权。 如果多个执行线程在不同步的情况下访问同一个shared_ptr,并且这些访问中的任何一个都使用了shared_ptr的非常量成员函数,则将发生数据争用;否则,将导致数据争用。 原子函数的shared_ptr重载可用于防止数据争用。
shared_ptr
变量不是线程安全的,并且如果一个或多个线程修改了该变量,则不应从多个线程访问该变量 。 管理同一指针的多个变量是原子的,每个线程可以自由修改其自己的shared_ptr
副本。
例如,这是不安全的:
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <thread>
int main()
{
std::shared_ptr< std::string > str( new std::string() );
std::vector< std::thread > threads;
for ( int i = 0; i < 10; i++ )
{
threads.emplace_back([&]
{
if ( str->empty() )
{
str.reset( new std::string( "thread string" ) );
}
else
{
str.reset();
}
});
}
for ( auto& thread : threads )
{
thread.join();
}
}
但这是因为线程不会修改str
变量,但是会增加其引用计数:
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <thread>
int main()
{
std::shared_ptr< std::string > str( new std::string() );
std::vector< std::thread > threads;
for ( int i = 0; i < 10; i++ )
{
threads.emplace_back([&]
{
std::shared_ptr< std::string > str2 = str;
if ( str2->empty() )
{
str2.reset( new std::string( "thread string" ) );
}
else
{
str2.reset();
}
});
}
for ( auto& thread : threads )
{
thread.join();
}
}
C ++ 20添加了std::atomic_shared_ptr
,这是完全线程安全的。 在此之前,您可以使用原子非成员函数。
在Swift中,引用计数是线程安全的,因为基础NSObject是线程安全的。 在这种情况下,引用计数是对象本身的固有属性,因此您的问题是没有意义的。 瓦拉看起来也是如此。
离开了C ++,总是迟到了。
std::shared_ptr
的引用计数的实现是线程安全的,正如Alan帖子中的引号清楚指出的那样,但显然告诉一个人开始照看另一个对象不是这样。
这样做并不普遍。 但这破坏了它的目的,当然,如果您要尝试这样做,则会使代码具有线程安全性。 有关cppreference的更多详细信息-operator operator=
某些重载是线程安全的,而某些不是。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.