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

Путаница в отношении оператора блокировки в С#

Это из MSDN: Ключевое слово блокировки гарантирует, что один поток не вводит критический раздел кода, а другой поток находится в критическом разделе.

Значит ли критический раздел такой же, как критический раздел?

Или это означает: Ключевое слово блокировки гарантирует, что один поток не вводит любой критический раздел, защищенный объектом кода, а другой поток находится в любом критическом разделе, защищенном тем же объектом.

    class Program
{
    static void Main(string[] args)
    {
        TestDifferentCriticalSections();

        Console.ReadLine();
    }

    private static void TestDifferentCriticalSections()
    {
        Test lo = new Test();

        Thread t1 = new Thread(() =>
        {
            lo.MethodA();
        });
        t1.Start();

        Thread t2 = new Thread(() =>
        {
            lo.MethodB();
        });
        t2.Start();
    }
}

public class Test
{
    private object obj = new object();

    public Test()
    { }

    public void MethodA()
    {
        lock (obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine("A");
            }
        }
    }

    public void MethodB()
    {
        lock (obj)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(500);
                Console.WriteLine("B");
            }
        }
    }
}
4b9b3361

Ответ 1

Вопрос смутно сформулирован, и ответы до сих пор также не очень ясны. Позвольте мне перефразировать вопрос на несколько вопросов:

(1) Задает ли оператор блокировки, что за один раз в тело оператора блокировки не более одного потока?

Нет. Например:

static readonly object lock1 = new object();
static readonly object lock2 = new object();
static int counter = 0;
static object M()
{
    int c = Interlocked.Increment(ref counter);
    return c % 2 == 0 ? lock1 : lock2;
}

...
lock(M()) { Critical(); }

Возможно, что два потока будут одновременно находиться в кубе оператора блокировки, потому что оператор блокировки блокируется на двух разных объектах. Thread Alpha может вызвать M() и получить lock1, а затем поток Beta может вызвать M() и получить lock2.

(2) Предполагая, что мой оператор блокировки всегда блокирует один и тот же объект, делает ли оператор блокировки гарантией, что не более одного "активного" потока находится в теле блокировки в любой момент?

Да. Если у вас есть:

static readonly object lock1 = new object();
...
lock(lock1) { Critical(); }

тогда поток Alpha может занять блокировку, а бета-версия потока будет заблокирована до тех пор, пока блокировка не будет доступна до ввода тела блокировки.

(3) Предполагая, что у меня есть два оператора блокировки, и оба оператора блокировки блокируются на одном и том же объекте каждый раз, делает ли оператор блокировки, чтобы не более чем один "активный" поток находился в теле любой блокировки на любом время?

Да. Если у вас есть:

static readonly object lock1 = new object();
...
static void X() 
{
    lock(lock1) { CriticalX(); }
}
static void Y() 
{
    lock(lock1) { CriticalY(); }
}

то если поток Alpha находится в X и берет блокировку, а поток Beta находится в Y, тогда бета-версия потока будет блокироваться до тех пор, пока блокировка не будет доступна до ввода тела блокировки.

(4) Почему вы помещаете "активные" в "кавычки"?

Чтобы обратить внимание на то, что ожидающий поток может находиться в корпусе замка. Вы можете использовать метод Monitor.Wait для "приостановки" потока, который находится в корпусе блокировки, и позволить заблокированному потоку стать активным и ввести тело блокировки (или другое тело блокировки, которое блокирует один и тот же объект). Ожидающая нить останется в состоянии ожидания, пока не будет пульсирована. Через некоторое время после его пульсирования он присоединяется к "готовой" очереди и блокирует до тех пор, пока в блокировке не будет "активного" потока. Затем он возобновляется в тот момент, когда он остановился.

Ответ 2

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

Пример:

public static object DatabaseLck= new object();

lock (DatabaseLck) {
        results = db.Query<T>(query).ToList();
     }

Или

lock (DatabaseLck) {
       results = db.Query<T>(string.Format(query, args)).ToList();
  }

Ни один из этих кодовых блоков не может быть запущен одновременно, ПОТОМУ ЧТО они используют один и тот же объект блокировки. Если вы использовали другой объект блокировки для каждого, они могли работать одновременно.

Ответ 3

Это один и тот же критический раздел.

lock (synclock)
{
  // the critical section protected by the lock statement
  // Only one thread can access this at any one time
}

См. Заявление о блокировке в MSDN:

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


Или это означает: ключевое слово lock гарантирует, что один поток не будет входить в критический раздел кода, а другой поток - в любой критический раздел.

Нет. Это не значит. Это означает, что критическая секция защищена этим замком и эта блокировка в одиночку.


Обновление, следуя примеру кода:

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

Ответ 4

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

Ответ 5

Нет, это означает, что другой поток не войдет в критический раздел, защищенный этим оператором блокировки.

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

Так перевод: Ключевое слово lock гарантирует, что один поток не войдет в раздел кода, защищенный lock, тогда как другой поток находится в этом разделе кода (защищенном lock)

Ответ 6

Критический раздел, о котором идет речь, - это раздел, защищенный операторами блокировки.

Любой критический раздел, который блокирует тот же объект, будет заблокирован от доступа.

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