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

Как заблокировать несколько объектов?

Я хочу заблокировать два объекта одновременно. Почему я не могу написать такой код?

lock (obj1, obj2)

Должен ли я всегда писать так?

lock (obj1)
{
    lock (obj2)
    {
    }
}

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

4b9b3361

Ответ 1

Это правильный способ блокировки нескольких объектов, да.

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

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

Вы также можете, как вы предлагаете, ввести один выделенный объект блокировки, но это сделает вашу блокировку более грубой. Все зависит от ваших потребностей. Если вам иногда нужен только один из замков, вы должны держать их отдельно (но обязательно сохраните порядок блокировки, как указано выше).

Ответ 2

Ну, этот вопрос слишком старый, но вот компактный, который я выяснил, оба кода будут доведены до тех же скомпилированных утверждений (это и одно в описании вопроса):

    lock (obj1) lock (obj2)
    {
        // your code
    }

Ответ 3

Если вы пишете такой код, вам нужно убедиться, что вы всегда блокируете эти два объекта в этом порядке. В противном случае вы можете столкнуться с тупиками.

Ответ 4

Причина, по которой вы должны сделать это, как вы ее написали, состоит в том, что вы не можете заблокировать два объекта за одно и то же время; Вы блокируете их один за другим (и очень важно сохранить порядок блокировки, иначе вы можете зайти в тупиковые ситуации), и вам лучше быть такими явными, как вы можете с этими вещами.

Ответ 5

Сделайте что-то вроде

    internal static void DuoEnter(object po1, object po2, int pnTimeOutMs = 1000)
    {
        if ((po1 == null) && (po2 == null))
            return;
        int nMaxLoops = 100 * pnTimeOutMs;
        bool lOneProcessor = Environment.ProcessorCount < 2;
        for (int nLoops = 0; nLoops < nMaxLoops; nLoops++)
        {
            if ((po1 == null) || (po2 == null) || (po1 == po2))
            {
                if (Monitor.TryEnter(po1 ?? po2))
                    return;
            }
            else
            {
                if (Monitor.TryEnter(po1))
                    if (Monitor.TryEnter(po2))
                        return;
                    else
                        Monitor.Exit(po1);
            }
            if (lOneProcessor || (nLoops % 100) == 99)
                Thread.Sleep(1); // Never use Thread.Sleep(0)
            else
                Thread.SpinWait(20);
        }
        throw new TimeoutException(
            "Waited more than 1000 mS trying to obtain locks on po1 and po2");
    }

    internal static void DuoExit(object po1, object po2)
    {
        if ((po1 == null) && (po2 == null))
            return;
        if (po1 == null || po2 == null || po1 == po2)
            Monitor.Exit(po2 ?? po1);
        else
        {
            Monitor.Exit(po2);
            Monitor.Exit(po1);
        }
    } 

Ответ 6

Я столкнулся с такой же проблемой и написал этот фрагмент, который может помочь вам, хотя он далек от совершенства:

private void MultiLock(object[] locks, WaitCallback pFunc, int index = 0)
{
    if (index < locks.Count())
    {
        lock (locks[index])
        {
            MultiLock(locks, pFunc, index + 1);
        }
    }
    else
    {
        ThreadPool.QueueUserWorkItem(pFunc);
    }
}

И тогда просто вызовите этот метод следующим образом:

public object LockedObject1 = new Object();
public object LockedObject2 = new Object();

public void MyFunction(object arg)
{
    WaitCallback pFunc = delegate
    {
        // Operations on locked objects
    }

    MultiLock(new object[] {LockedObject1, LockedObject2}, pFunc);
}

Ответ 7

Вместо того, чтобы блокировать сами объекты, вы создаете выделенный объект под названием PadLock или похожий и только блокируете его там, где это необходимо.

Ответ 8

Блокировка здесь не означает, что при длительности блокировки никакой другой код в другом потоке не может получить доступ или изменить объект. Если вы заблокируете объект, любой другой поток может одновременно изменить объект. Блок блокировки кода позволяет вам сделать код внутри блока блокировки единым, т.е. Один поток может выполнять блок блокировки блокировки один раз, а другие потоки, которые пытаются выполнить один и тот же блок кода, должны будут ждать, пока владелец поток выполняется с выполнением блока кода. Поэтому в основном вам не нужно блокировать 2 или более объектов в обычных случаях. Блокировка вашей цели состоит в том, чтобы сделать единичную запись блока кода