2009-09-19 7 views
5

Я задал этот вопрос в интервью # .net/C:Сделки - Как избежать взаимоблокировок?

Если мы имеем две нити Т1 и Т2. T1 получает блокировку на obj1 и затем выполняет некоторую обработку и получает блокировку на obj2. T2 получает блокировку на obj2 и , затем выполняет некоторую обработку и приобретает замок на obj1. Таким образом, мы можем иметь тупик . Что общего метода , который мы используем в многопоточности, чтобы избежать этой ситуации?

Я ответил сказав, что T1 и T2 должны иметь некоторый механизм для связи, и мы должны сделать кодирование таким образом, что T2 начинает делать свою работу только после того, как T1 сигнализировал, что это делается с его работой. Интервьюер спросил меня, знаю ли я о транзакциях и как мы можем использовать его, чтобы встретить эту тупиковую ситуацию. У меня есть много опыта многопоточности на стороне пользовательского интерфейса в winforms. Но я никогда не использовал транзакции. Может кто-нибудь рассказать мне больше об этом или указать мне на url/book,

ответ

7

Один общий подход, чтобы избежать взаимоблокировок - обеспечить, чтобы ваши потоки/процессы приобретали блокировки ресурсов в том же порядке. например, T2 должен сначала блокировать obj1, а затем obj2 (то же, что и T1).

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

Если формулировка в вашей цитате была точным вопросом, она плохо написана. Оно должно быть:

T1 получает блокировку на obj1, делает что-то, а затем пытается также заблокировать obj2 без разблокировки obj1. В то же время T2 приобретает замок на obj2, делает что-то и затем пытается также заблокировать obj1 без разблокировки obj2. A произойдет взаимоблокировка.

Я настоятельно рекомендую прочитать Concurrent Programming on Windows от Joe Duffy. Это, наверное, самая полная книга по теории и практике потоковой обработки для Windows.

+0

@ Аш Я получаю возможность приобретения замков в том же порядке. Но что же это за транзакции? – Sandbox

+1

@Sandbox, мне кажется, что они говорят о «транзакции» в общем смысле, гарантируя, что куча отдельных операций выполняется как одна (то есть атомарно). В базе данных это достигается с помощью ключевого слова Begin Transaction, в .net оно выполняется (обычно) с помощью оператора блокировки. В моем ответе я добавил очень рекомендуемую книгу Джо Даффи. – Ash

3

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

Чтобы увидеть проблему с другого конца, см. Dijkstra's banker's algorithm.

1

Я не совсем уверен, где совершаются транзакции непосредственно в этом, кроме возможности откат. Главное, чтобы ИМО собирал замки в последовательном порядке и рано; о, и используйте тайм-аут, когда приобретаете замки - не сидите там, застряв навсегда.

Ссылка сделок заставляет меня думать, в первую очередь из баз данных, в этом случае еще одно соображение заключается в использовании трюков, как UPDLOCK, чтобы убедиться, что вы получите блокировку записи первоначально, чтобы избежать проблем, способствующие (оспариваемого) для чтения замок к записи -lock (переход от тупиковой ситуации к простой блокировке). Конечно, во многих базах данных также обнаружено более тупиковое обнаружение, чем у большинства обычных кодов.

+0

Я думаю, что термин «транзакция» в общем случае означает, что несколько неатомных операций выполняются как атомарные. Обычным решением является использование блокировки. – Zed

1

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

Теперь пусть каждый поток из примера использует свою собственную транзакцию (в базе данных, файловой системе Vista или других интерфейсах, поддерживающих транзакции). Если происходит тупиковая ситуация (может быть легко обнаружена, когда это произойдет), вы выберете один из потоков, которые являются частью тупика (жертвы), и откат его транзакции. Это освободит блокировки, чтобы оставшаяся нить могла продолжить. Потребительский поток может повторить транзакцию последней.

Если вероятность тупика низкая относительно стоимости повторной транзакции, это может быть полезным решением.

Смежные вопросы