锁定IHostedService

时间:2019-04-17 21:47:31

标签: c# multithreading asp.net-core

我有IHostedService继承者服务,可以处理一些数据,并将最后一部分存储在变量中。

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

    public void ProcessNextPart()
    {
        ...
    } 
}

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

谢谢。

1 个答案:

答案 0 :(得分:1)

这完全取决于DataType是类还是结构。

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

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字节),则写入不是原子的。即使该结构足够小,我也不建议您依赖它,因为您以后可以添加更多字段并破坏此代码。因此,您有两种解决方案:要么使用锁,要么将值装箱。

使用锁:

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);
    } 
}