Подтвердить что ты не робот

Выйти из метода, если другой поток выполняет его

У меня есть метод в многопоточном приложении, и мне нравится следующее поведение при вызове этого метода:

  • Если ни один другой поток не выполняет этот метод, выполните его.
  • Если другой поток в настоящее время выполняет метод, то выйдите из метода, не выполнив его.

Оператор lock в С# полезен для ожидания, пока поток завершит выполнение, но я не хочу сериализовать доступ к этому методу, а скорее обходить выполнение указанного метода, если он выполняется другим потоком.

4b9b3361

Ответ 1

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

В любом случае вы можете использовать Monitor.TryEnter(). Он не блокирует и возвращает false, если он не может получить блокировку. В этом случае вы можете просто вернуться из функции.

Ответ 2

Вы можете сделать это с помощью Monitor.TryEnter, но, возможно, проще: Interlocked:

int executing; // make this static if you want this one-caller-only to
               // all objects instead of a single object
void Foo() {
    bool won = false;
    try {
        won = Interlocked.CompareExchange(ref executing, 1, 0) == 0;
        if(won) {
           // your code here
        }
    } finally {
        if(won) Interlocked.Exchange(ref executing, 0);
    }

}

Ответ 3

создать переменную bool в другом месте, установить значение true при запуске и false при выходе из метода, перед запуском метода проверить, является ли переменная false, а затем запустить else exit из метода

Ответ 4

Здесь вспомогательный метод для этой цели:

static class Throttle
{
    public static void RunExclusive(ref int isRunning, Action action)
    {
        if (isRunning > 0) return;

        bool locked = false;
        try
        {
            try { }
            finally
            {
                locked = Interlocked.CompareExchange(ref isRunning, 1, 0) == 0;
            }

            if (locked) action();
        }
        finally 
        { 
            if (locked) 
                Interlocked.Exchange(ref isRunning, 0); 
        }
    }
}

и используйте его как:

private int _isTuning = 0;
private void Tune() { ... }

...

Throttle.RunExclusive(ref _isTuning, Tune);