Как я могу заблокировать функцию для вызывающего и немедленно вернуть других вызывающих? - PullRequest
0 голосов
/ 18 января 2019

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

Это мой подход в C #:

public ErrorCodes SomeFunction()
{
  lock(_lock)
  {
    if(_beingUsed)
      return ErrorCodes.BeingUsed;

    _beingUsed = true;
  }

  // Time consuming code that is not thread safe.

  lock(_lock)
  {
    _beingUsed = false;
  }
}

Но я не смог найти ничего похожего или другого решения моей проблемы. Это достаточно хорошо? У вас есть лучшие предложения?

1 Ответ

0 голосов
/ 29 января 2019

У меня есть пара улучшений для вашего подхода.

1) Вам нужно добавить try-finally блок, чтобы установить _beingUsed = false гарантированно. В противном случае, если трудоемкий код выдаст исключение, ни один вызывающий не сможет запустить этот код.

2) Поскольку код ниже первой блокировки доступен только для одного абонента, я не вижу необходимости во второй блокировке.

Вот улучшенный код:

public ErrorCodes SomeFunction()
{
    lock(_lock)
    {
        if(_beingUsed)
          return ErrorCodes.BeingUsed;

        _beingUsed = true;
    }

    // here can enter only one caller
    try
    {
        // Time consuming code that is not thread safe.
        return ErrorCodes.OK;
    }
    finally
    {
        _beingUsed = false;
    }
}

Если производительность очень критична, вы можете рассмотреть подход без блокировки:

int _flag = 0;
public ErrorCodes SomeFunction()
{
    if (Interlocked.Exchange(ref _flag, 1) == 0)
    {
        // here can enter only one caller
        try
        {
            //process long operation
            return ErrorCodes.OK;
        }
        finally
        {
            Interlocked.Exchange(ref _flag, 0);
        }

    }
    else
    {
        //immediately return
        return ErrorCodes.BeingUsed;
    }
}

Но этот код выглядит более сложным и требует понимания программирования без блокировки.

...