Проблемы взаимоблокировок и блокировок при использовании директивы @synchronized в задаче c - PullRequest
3 голосов
/ 13 апреля 2011

из яблочного "Руководства по программированию потоков" Я читал, что "Лучший способ избежать ситуаций взаимной блокировки и прямой блокировки - это брать только одну блокировку за один раз". Если я предпочитаю использовать директиву @synchronized в своем коде, это означает, что я должен сделать что-то вроде этого:

@ synchronized (aObj) {

@synchronized(bObj) {

    // do sth with the aObj and bObj here     
} 

}

вместо этого:

@ synchronized (aObj, bObj) {

 // do sth with the aObj and bObj here

}

?? если нет, то что значит «Один замок за раз?». Спасибо ...

Ответы [ 3 ]

9 голосов
/ 13 апреля 2011

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

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

Неважно, пытаетесь ли вы распределить все необходимые блокировки за один удар или в течение значительного периода времени, если порядок соответствует. Другими словами, никогда не делайте:

Thread A        Thread B
========        ========
lock a          lock b
lock b          lock a

Это может привести к последовательности:

  • A запирает.
  • B замки б.
  • A пытается заблокировать b, останавливается и ждет.
  • B пытается заблокировать a, останавливается и ждет.

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

Если вы измените поток B, чтобы он заблокировал a и b в этом порядке, тупик станет невозможным.

1 голос
/ 19 июня 2012

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

 @synchronized(MIN(a, b))
    {
        @synchronized(MAX(a, b))
        {
            // do stuff, safely
        }
    }

Это работает и с другими конструкциями блокировки. как:

 NSLock *a = [[NSLock alloc] init];
    NSLock *b = [[NSLock alloc] init];

    [MIN(a, b) lock];
    [MAX(a, b) lock];

    [MAX(a, b) unlock];
    [MIN(a, b) unlock];
0 голосов
/ 09 мая 2015

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

@synchronized (obj1) { ... }
@synchronized (obj2) { ... }

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...