Как решить проблему многопоточности в массивах

#multithreading #asynchronous #async-await #locking #deadlock

Вопрос:

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

Сначала они спросили меня, как решить простую тупиковую проблему, такую как

 lock(a) {  lock(b) {  // do smth  } }  lock(b) {  lock(a) {  // do smth  } }  

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

Вот идет какой-то псевдокод (потому что он не имеет отношения к языку и потому что я не помню, что именно там было).

 function void foo(T[] arr) {  lock(arr[randint(arr.length)]) {  lock(arr[randint(arr.length)]) {  // do smth  }  } }  var arr = new arr{...}  async () =gt; {  foo(arr)  foo(arr) }  

Вопрос в следующем: Как решить эту проблему автоматически UPD: это было интервью на C#, так что, возможно, только на этом языке есть инструменты для решения этой проблемы (я так не думаю, но это следует отметить, чтобы не вызвать недоразумений).

Комментарии:

1. К вашему сведению: Эта головоломка иллюстрирует, как возникают тупики в реальных программах. В другом варианте блокировки передаются функции в виде двух аргументов. Подсказка: Решение для версии массива немного более очевидно, потому что каждая из блокировок имеет свой собственный уникальный индекс в массиве.

Ответ №1:

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

Комментарии:

1. Я не видел вашего вопроса до сих пор, но, как утверждает Соломон в комментариях, обрабатывать массивы легко. Зафиксируйте индексы в порядке возрастания. Потокобезопасные коллекции здесь не являются ответом, потому что потокобезопасные коллекции не решают заданный вами вопрос. Массивы совершенно безопасны для доступа к перекрестным потокам, но если вам нужно ввести блокировки вокруг элементов, потокобезопасные коллекции вам не помогут.