Блокировка в IHostedService - PullRequest
       9

Блокировка в IHostedService

0 голосов
/ 18 апреля 2019

У меня есть IHostedService служба наследника, которая обрабатывает некоторые данные и сохраняет последнюю часть в переменной.

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

    public void ProcessNextPart()
    {
        ...
    } 
}

У меня также есть контроллер API, который использует DI для вызова MyService. Должен ли я использовать lock или какой-то другой подход для lastData в этом случае? Как я понимаю, возможно одновременное чтение (из контроллера) и запись (из службы) для этой переменной?

Спасибо.

1 Ответ

1 голос
/ 18 апреля 2019

Все зависит от того, является ли DataType классом или структурой.

Если это класс, то писать его можно атомарно, так что это в значительной степени безопасно. Если вы считаете, что вызывающая сторона может использовать это значение в цикле, то вы можете добавить энергозависимое чтение, чтобы предотвратить кэширование значения в регистре:

public class MyService : IHostedService 
{
    private DataType lastData;

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

    public void ProcessNextPart()
    {
        lastData = newValue;
    } 
}

Но, учитывая вариант использования, это звучит крайне маловероятно.

Если DataType - это структура, тогда это совсем другая история. Если структура больше, чем размер указателя на целевую архитектуру (4 байта для x86, 8 байтов для x64), то ее запись не является атомарной. Даже если структура достаточно мала, я не рекомендую полагаться на нее, так как вы можете добавить больше полей позже и нарушить этот код. Таким образом, у вас есть два решения: либо использовать блокировку, либо указать значение.

Использование блокировки:

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);
    } 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...