Есть ли в C# операция «попробуй заблокировать, пропустить, если истекло время ожидания»?

StackOverflow https://stackoverflow.com/questions/8546

  •  08-06-2019
  •  | 
  •  

Вопрос

Мне нужно попытаться заблокировать объект, и если он уже заблокирован, просто продолжить (по истечении времени или без него).

Оператор блокировки C# блокирует.

Это было полезно?

Решение

Я считаю, что вы можете использовать Monitor.TryEnter().

Оператор блокировки просто преобразуется в Monitor.Enter() звонок и try catch блокировать.

Другие советы

У Эда есть подходящая для вас функция.Только не забудь позвонить Monitor.Exit().Вам следует использовать try-finally блокируйте, чтобы гарантировать правильную очистку.

if (Monitor.TryEnter(someObject))
{
    try
    {
        // use object
    }
    finally
    {
        Monitor.Exit(someObject);
    }
}

У меня была та же проблема, в итоге я создал класс TryLock который реализует IDisposable, а затем использует using оператор для управления областью действия блокировки:

public class TryLock : IDisposable
{
    private object locked;

    public bool HasLock { get; private set; }

    public TryLock(object obj)
    {
        if (Monitor.TryEnter(obj))
        {
            HasLock = true;
            locked = obj;
        }
    }

    public void Dispose()
    {
        if (HasLock)
        {
            Monitor.Exit(locked);
            locked = null;
            HasLock = false;
        }
    }
}

А затем используйте следующий синтаксис для блокировки:

var obj = new object();

using (var tryLock = new TryLock(obj))
{
    if (tryLock.HasLock)
    {
        Console.WriteLine("Lock acquired..");
    }
}

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

Книга Джеффа Рихтера «CLR Via C#» — отличная книга о деталях внутреннего устройства CLR, если вы занимаетесь более сложными вещами.

Рассмотрите возможность использования AutoResetEvent и его метода WaitOne с вводом тайм-аута.

static AutoResetEvent autoEvent = new AutoResetEvent(true);
if(autoEvent.WaitOne(0))
{
    //start critical section
    Console.WriteLine("no other thread here, do your job");
    Thread.Sleep(5000);
    //end critical section
    autoEvent.Set();
}
else
{
    Console.WriteLine("A thread working already at this time.");
}

Видеть https://msdn.microsoft.com/en-us/library/cc189907(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx и https://msdn.microsoft.com/en-us/library/cc190477(v=vs.110).aspx

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top