Создание тупика - PullRequest
       13

Создание тупика

4 голосов
/ 20 октября 2011

У меня есть код, который выглядит следующим образом.Создает ли это тупик?

private readonly object objectLock = new object();

public void MethodA()
{
    lock(objectLock)
    {
       MethodB();
    }
}

public void MethodB()
{
    lock(objectLock)
    {
      //do something
    }
}

ОБНОВЛЕНИЕ: Будет запущено 2 потока

Ответы [ 5 ]

11 голосов
/ 20 октября 2011

Нет - но это будет:

private readonly object objectLockA = new object();
private readonly object objectLockB = new object();

public void MethodA()
{
    lock(objectLockA)
    {
    lock(objectLockB)
    {
       //...
    }
    }
}

public void MethodB()
{
    lock(objectLockB)
    {
    lock(objectLockA)
    {
      //do something
    }
    }
}

Если вы вызовете оба метода параллельно (из двух разных потоков), вы получите тупик ...

6 голосов
/ 20 октября 2011

Нет, это не тупик. Это та же самая блокировка потока на том же объекте синхронизации. Поток может принимать вложенные блокировки. Просто нужно выпустить его равным нет. раз.

3 голосов
/ 20 октября 2011

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

Вызов MethodA производит следующую последовательность операций в том же потоке:

  • Блокировка objectLock.
  • Звоните MethodB.
  • Замок objectLock.
  • Разблокировать objectLock.
  • Выход MethodB.
  • Разблокировать objectLock.

Итак, objectLock заблокирован дважды и не заблокирован дважды, но тупика нет:

  • Если другой поток попытается вызвать MethodA, он просто заблокирует первую блокировку, но не заблокируется.
  • Если звонит MethodB, то же самое произойдет.
  • И если первый поток вызовет MethodB, а затем другой поток вызовет MethodA, снова произойдет «нормальная» блокировка, но не тупик.
3 голосов
/ 20 октября 2011

Нет, вам нужно два объекта блокировки, чтобы включить тупик.

1 голос
/ 26 августа 2018

При копировании вставьте следующие строки, скомпилируйте и запустите, чтобы увидеть, что «никогда не вызывается» не печатается в консоли.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace deadlocktest
{
    class Program
    {
    static object object1 = new object();
    static object object2 = new object();

    public static void FunctionOne()
    {
        lock (object1)
        {
            Console.WriteLine("FunctionOne called 1");
            Thread.Sleep(1000);
            lock (object2)
            {
                Console.WriteLine("FunctionOne called 2, never called");
            }
        }
    }

    public static void FunctionTwo()
    {
        lock (object2)
        {
            Console.WriteLine("FunctionTwo called 1");
            Thread.Sleep(1000);
            lock (object1)
            {
                Console.WriteLine("FunctionTwo called 2, never called");
            }
        }
    }

    static void Main(string[] args)
    {

        Thread thread1 = new Thread(FunctionOne);
        Thread thread2 = new Thread(FunctionTwo);
        thread1.Start();
        thread2.Start();
        int i = 0;
        while (i < 9)
        {
            Console.WriteLine("How bad thread!");
            i++;
        }
        thread1.Join();
        thread2.Join();
        Console.ReadLine();
    }
}

}

...