Выйти из метода, если другой поток выполняет его
У меня есть метод в многопоточном приложении, и мне нравится следующее поведение при вызове этого метода:
- Если ни один другой поток не выполняет этот метод, выполните его.
- Если другой поток в настоящее время выполняет метод, то выйдите из метода, не выполнив его.
Оператор lock
в С# полезен для ожидания, пока поток завершит выполнение, но я не хочу сериализовать доступ к этому методу, а скорее обходить выполнение указанного метода, если он выполняется другим потоком.
Ответы
Ответ 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);