c++ - 自动引用计数系统中的赋值是线程安全的吗?
问题描述
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
完全线程安全的。在此之前,您可以使用原子非成员函数。
推荐阅读
- sql - 在sql server中使用左连接时如何对2条记录求和?
- php - 使用 OpenTBS 的 2 级表上的“bmagnet”参数问题
- xslt - XSLT 对子段进行排序和分组以及重复父段
- ios - Flutter 包振动 0.0.4 在 iOS 中不起作用
- java - 有没有办法用唯一的配置文件编译类并排除它?
- java - 在特定条件下 for 循环的奇怪行为。加工
- angular - 如何根据@ngrx 中的路由获取数据?
- javascript - 页面之间的路由
& 返回主页 - ReactJS - amazon-s3 - 使用 FileHiveMetastore 的 S3 上的 Presto DDL 不起作用
- c# - 在参数中传递“特殊字符组合”作为密码时,HTTPWebResponse 无法流式传输响应