Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在ASP.NET核心Web Api中用联锁的.Exchange(ref oldValue,newValue)替换不可变的数据结构安全吗_C#_Asp.net Core_.net Core_Atomic - Fatal编程技术网

C# 在ASP.NET核心Web Api中用联锁的.Exchange(ref oldValue,newValue)替换不可变的数据结构安全吗

C# 在ASP.NET核心Web Api中用联锁的.Exchange(ref oldValue,newValue)替换不可变的数据结构安全吗,c#,asp.net-core,.net-core,atomic,C#,Asp.net Core,.net Core,Atomic,我有一个api,它是地理坐标请求的终点。这意味着用户可以搜索他们所在区域的特定位置。同时,可以添加新的位置。为了使查询尽可能快,我想我应该使R-树保持不变。也就是说,R-树中没有锁,因为多个线程可以同时读取,而没有争用条件。收集更新,如果收集了100个更新,我想创建一个新的R树并替换旧的R树。现在我的问题是如何做到最好 我有一个SearchService,它存储为单音,并有一个R树作为私有实例 在我的Startup.cs中 services.AddSingleton<ISearchServ

我有一个api,它是地理坐标请求的终点。这意味着用户可以搜索他们所在区域的特定位置。同时,可以添加新的位置。为了使查询尽可能快,我想我应该使R-树保持不变。也就是说,R-树中没有锁,因为多个线程可以同时读取,而没有争用条件。收集更新,如果收集了100个更新,我想创建一个新的R树并替换旧的R树。现在我的问题是如何做到最好

我有一个SearchService,它存储为单音,并有一个R树作为私有实例

在我的Startup.cs中

services.AddSingleton<ISearchService, SearchService>();
services.AddSingleton();
ISearchService.cs

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

    void Update(IEnumerable<GeoLocation> data);
}
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);
    }
}
公共接口ISearchService
{
IEnumerable Get(RTreeQuery);
无效更新(IEnumerable数据);
}
SearchService.cs

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

    void Update(IEnumerable<GeoLocation> data);
}
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);
    }
}
公共类搜索服务:ISearchService
{
私有RTree-RTree;
公共IEnumerable Get(RTreeQuery查询)
{
返回rTree.Get(查询);
}
公共无效更新(IEnumerable数据)
{
var newTree=新的RTree(数据);
联锁交换(参考rTree、newTree);
}
}
我的问题是,如果我用Interlock.exchange()交换引用,操作是原子的,应该没有竞争条件。但是,如果线程仍然使用旧实例来处理其请求,会发生什么呢。垃圾收集器是否会在线程仍然访问旧实例时删除它?毕竟,不再有对旧实例的引用

我对这个话题比较陌生,所以欢迎任何帮助。谢谢你的支持

对引用的读写是原子的,这意味着不会有对齐问题。然而,它们可能是陈腐的

CLI规范第12.6.6节

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

关于GC,您的树在运行
Get
时不会被垃圾收集


总之,就引用原子性而言,您的方法是线程安全的,您还可以使用
更新
方法并安全地覆盖引用,而不需要
联锁。Exchange
。当前实现中可能出现的最糟糕情况是,您只得到了一个陈旧的树,您提到的树不是问题。

@MichaelRandall感谢您的评论。目前,所有线程都使用同一个SearchService实例,因此在同一个R树实例上。你对如何解决这样的问题有什么建议吗?如果线程使用过时的版本就可以了。但是我不想为每个请求构造R树。@MichaelRandall这样垃圾收集器或其他东西就不会有问题了?如果你喜欢,你可以把它作为一个答案,我会接受:)。非常感谢你的帮助@MichaelRandall不想惹你生气,但是如果你有时间,你仍然可以回答这个问题,这样其他有类似问题的人就可以马上得到解决方案。