用ASP.NET Core Web-Api中的Interlocked.Exchange(ref oldValue,newValue)替换不可变数据结构是否安全

问题描述 投票:4回答:1

我有一个api,它是地理坐标请求的终点。这意味着用户可以搜索其区域中的特定位置。同时可以添加新位置。为了使查询尽可能快,我认为我将使R树不可更改。也就是说,R-Tree中没有锁,因为多个线程可以在没有竞争条件的情况下同时读取。更新被收集,例如收集了100个更新,我想创建一个新的R-Tree并替换旧的R-Tree。现在我的问题是如何做到最好?

我有一个SearchService,它以单音形式存储,并具有R-Tree作为私有实例。

在我的Startup.cs中

services.AddSingleton<ISearchService, SearchService>();

ISearchService.cs

public interface ISearchService
{
    IEnumerable<GeoLocation> Get(RTreeQuery query);

    void Update(IEnumerable<GeoLocation> data);
}

SearchService.cs

public class SearchService : ISearchService
{
    private RTree rTree;

    public IEnumerable<GeoLocation> Get(RTreeQuery query)
    {
        return rTree.Get(query);
    }

    public void Update(IEnumerable<GeoLocation> data)
    {
        var newTree = new RTree(data);

        Interlocked.Exchange<RTree>(ref rTree, newTree);
    }
}

我的问题是,如果我与Interlock.Exchange()交换引用,则该操作是原子性的,应该没有竞争条件。但是,如果线程仍然使用旧实例来处理其请求,将会发生什么。可能是垃圾回收器在线程仍访问旧实例时删除了它吗?毕竟,不再有对旧实例的引用。

我对这个话题还比较陌生,欢迎大家提供帮助。感谢您的支持!

c# asp.net-core .net-core atomic
1个回答
1
投票

references的读写是atomic,这意味着不存在对齐问题。但是,它们可能会过时。

CLI规范的第12.6.6节

除非显式布局控件(请参阅分区II(控制实例)布局))用于更改默认行为,数据元素否大于自然字大小(本机int的大小)应为正确对齐。对象引用应被视为以本机字大小存储。

关于GC,您的树在运行时是安全的Get

因此,总的来说,您的方法就线程而言是安全的,您也可以使用Update方法并安全地覆盖reference,不需要Interlocked.Exchange。当前实现中可能发生的最坏情况是,您只会得到一棵陈旧的树,而您提到的这不是问题。

© www.soinside.com 2019 - 2024. All rights reserved.