Пример кода для иллюстрирования мертвой блокировки при помощи блокировки (это)

Я не знаю, есть ли хороший способ сделать то, что ты хочешь. Чтобы немного приблизиться, вы можете добавить этот атрибут для извлечения непосредственно из URL

[HttpGet]
public ActionResult Get([FromUri]SubmitModel model)
{ 
   // this endpoint returns a 400 bad request
   return Ok();
}

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

29
задан jdehaan 16 February 2011 в 22:17
поделиться

5 ответов

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

Итак, простой пример:

// thread 1
lock(typeof(int)) {
  Thread.Sleep(1000);
  lock(typeof(float)) {
    Console.WriteLine("Thread 1 got both locks");
  }

}

// thread 2
lock(typeof(float)) {
  Thread.Sleep(1000);
  lock(typeof(int)) {
    Console.WriteLine("Thread 2 got both locks");
  }
}

Предполагая, что оба потока запускаются в течение секунды друг от друга, они оба успеют захватить первую блокировку, прежде чем кто-либо дойдет до внутренней блокировки. Без вызова Sleep () один из потоков, скорее всего, успел бы получить и снять обе блокировки до того, как другой поток даже запустится.

32
ответ дан 28 November 2019 в 01:51
поделиться

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

Объекты типа - это синглтоны, видимые для каждого фрагмента кода .net, и вы не можете контролировать, кто блокирует ваш «this» объект извне.

То же самое относится и к строкам: поскольку строки являются неизменяемыми, фреймворк хранит только один экземпляр «жестко закодированных» строк и помещает их в пул (строка называется интернированной), если вы пишете два раза в код строка "привет", вы всегда получите один и тот же объект.

Рассмотрим следующий пример: вы написали только Thread1 в своем суперприватном вызове, а Thread2 вызывается некоторой библиотекой, которую вы используете в фоновом потоке ...

void Thread1()
{
  lock (typeof(int))
  {
    Thread.Sleep(1000);
    lock (typeof(long))
      // do something
  }
}

void Thread2()
{
  lock (typeof(long))
  {
    Thread.Sleep(1000);
    lock (typeof(int))
      // do something
  }
}
4
ответ дан Maghis 28 November 2019 в 01:51
поделиться

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

Например:

using System;
using System.Threading;

namespace ThreadLock
{
    class Program
    {
        static void Main(string[] args)
        {
            lock ("my lock")
            {
                ManualResetEvent evt = new ManualResetEvent(false);
                WorkerObject worker = new WorkerObject(evt);
                Thread t = new Thread(new ThreadStart(worker.Work));
                t.Start();
                evt.WaitOne();
            }
        }
    }

    class WorkerObject
    {
        private ManualResetEvent _evt;
        public WorkerObject(ManualResetEvent evt)
        {
            _evt = evt;
        }
        public void Work()
        {
            lock ("my lock")
            {
                Console.WriteLine("worked.");
                _evt.Set();
            }
        }
    }
}

В этом случае вызывающий код создает блокировку строки, а затем создает рабочий объект. Рабочий объект в Work () блокируется на той же строке, которая является одиночной в C #. Он оказывается в тупике, потому что вызывающий абонент владеет блокировкой и ожидает сигнала, который никогда не придет.

-1
ответ дан plinth 28 November 2019 в 01:51
поделиться

Это довольно стандартная злоба. Вытаскивать замки из строя, а затем спать с замком. Две плохие дела. :)

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

namespace DeadLock
{
    public class Program
    {
        static void Main(string[] args)
        {
            var ddt = new DontDoThat();

            ddt.Go();
        }
    }

    public class DontDoThat
    {
        private int _badSharedState = 0;
        private readonly object _lock1 = new object();
        private readonly object _lock2 = new object();

        public void Go()
        {
            new Thread(BadGuy1).Start();
            new Thread(BadGuy2).Start();

            Console.WriteLine("Leaving Go!");
        }

        public void BadGuy1()
        {
            lock (_lock1)
            {
                Thread.Sleep(100); // yeild with the lock is bad
                lock (_lock2)
                {
                    _badSharedState++;
                    Console.Write("From Bad Guy #1: {0})", _badSharedState );
                }
            }
        }
        public void BadGuy2()
        {
            lock (_lock2)
            {
                lock (_lock1)
                {
                    _badSharedState++;
                    Console.Write("From Bad Guy #2: {0})", _badSharedState);
                }
            }
        }
    }
}
2
ответ дан 28 November 2019 в 01:51
поделиться

Конечно, вот так.

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

Для Например, два потока, которые блокируются следующим образом:

Thread 1               Thread 2
 Lock "A"               Lock "B"
 Lock "B"               Lock "A" <-- both threads will stop dead here
                                     waiting for the lock to be come
                                     available.

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

using System;
using System.Threading;

namespace ConsoleApplication7
{
    public class Program
    {
        public static void Main(string[] args)
        {
            LockableClass lockable = new LockableClass();
            new Thread(new ParameterizedThreadStart(BackgroundMethod)).Start(lockable);
            Thread.Sleep(500);
            Console.Out.WriteLine("calling Reset");
            lockable.Reset();
        }

        private static void BackgroundMethod(Object lockable)
        {
            lock (lockable)
            {
                Console.Out.WriteLine("background thread got lock now");
                Thread.Sleep(Timeout.Infinite);
            }
        }
    }

    public class LockableClass
    {
        public Int32 Value1 { get; set; }
        public Int32 Value2 { get; set; }

        public void Reset()
        {
            Console.Out.WriteLine("attempting to lock on object");
            lock (this)
            {
                Console.Out.WriteLine("main thread got lock now");
                Value1 = 0;
                Value2 = 0;
            }
        }
    }

}
3
ответ дан 28 November 2019 в 01:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: