C# 锁定IHostedService

C# 锁定IHostedService,c#,multithreading,asp.net-core,C#,Multithreading,Asp.net Core,我有IHostedServiceinheritor服务,处理一些数据,并将最后一部分存储在变量中 public class MyService : IHostedService { private DataType lastData; public DataType GetLastData() { return lastData; } public void ProcessNextPart() { ...

我有
IHostedService
inheritor服务,处理一些数据,并将最后一部分存储在变量中

public class MyService : IHostedService 
{
    private DataType lastData;
    public DataType GetLastData()
    {
       return lastData;
    }

    public void ProcessNextPart()
    {
        ...
    } 
}
我还有api控制器,它使用DI调用
MyService
。 在这种情况下,我应该对
lastData
使用
lock
还是其他方法?据我所知,可以同时读取(从控制器)和写入(从服务)该变量吗


谢谢。

这取决于
数据类型是类还是结构

如果它是一个类,那么编写它是原子的,所以它非常安全。如果您认为调用方可以在循环中使用该值,那么您可能需要添加一个易失性读取,以防止该值被缓存在寄存器中:

public class MyService : IHostedService 
{
    private DataType lastData;

    public DataType GetLastData()
    {
       return Volatile.Read(ref lastData);
    }

    public void ProcessNextPart()
    {
        lastData = newValue;
    } 
}
但是考虑到用例,这听起来很不可能

如果
DataType
是一个结构,那么它就是一个完全不同的故事。如果结构大于目标体系结构指针大小(x86为4字节,x64为8字节),则写入它不是原子的。即使struct足够小,我也不建议依赖它,因为您可以稍后添加更多字段并破坏此代码。所以有两种解决方案:要么使用锁,要么将值框起来

使用锁:

public class MyService : IHostedService 
{
    private readonly object syncRoot = new object();
    private DataType lastData;

    public DataType GetLastData()
    {
       lock (syncRoot)
           return lastData;
    }

    public void ProcessNextPart()
    {
        lock (syncRoot)
            lastData = newValue;
    } 
}
装箱值:

using System.Runtime.CompilerServices;

public class MyService : IHostedService 
{
    private readonly object syncRoot = new object();
    private StrongBox<DataType> lastData;

    public DataType GetLastData()
    {
        return lastData.Value;
    }

    public void ProcessNextPart()
    {
        lastData = new StrongBox<DataType>(newValue);
    } 
}
使用System.Runtime.CompilerServices;
公共类MyService:IHostedService
{
私有只读对象syncRoot=新对象();
私人保险箱数据;
公共数据类型GetLastData()
{
返回lastData.Value;
}
public void ProcessNextPart()
{
lastData=新的保险箱(newValue);
} 
}

MyService的目的是什么?对于
IHostedService
,它用于处理长任务或与请求无关的任务。您需要从controller调用
MyService
的原因是什么?作为托管服务,您希望在MyService中实现什么,以及您希望通过MyService从controller中实现什么?MyService与请求无关,它在后台进行计算。客户端可以使用控制器请求处理数据的最后一部分。所以关键是多线程使用变量,最后一部分存储在这里。如果
DataType
是一个类,没有任何锁定机制就可以了。如果它是一个结构,那么编写它可能不是原子的,在这种情况下,您应该添加一个锁或值框谢谢您的回答。对于List和nullable(例如int?)来说,第一种情况是真的吗?
List
是一个类,所以它是第一种情况
Nullable
是一个结构,所以第二种情况