Является ли блокировка (многопоточность) атомарной? - PullRequest
11 голосов
/ 06 февраля 2010

Это может звучать глупо, но если заблокировать ресурс в многопоточном приложении, то операция, выполняемая с ресурсом, выполняется атомарно?

I.E .: может ли процессор быть прерван или переключение контекста происходит, когда этот ресурс заблокирован? Если это так, то ничто другое не может получить доступ к этому ресурсу, пока он не будет запланирован, чтобы завершить свой процесс. Звучит как дорогая операция.

Ответы [ 4 ]

16 голосов
/ 06 февраля 2010

Процессор вполне может переключиться на другой поток, да. Действительно, на большинстве современных компьютеров в любом случае может быть одновременно запущено несколько потоков. Блокировка просто гарантирует, что никакой другой поток не сможет получить такую ​​же блокировку, поэтому вы можете убедиться, что операция с этим ресурсом является атомарной в терминах этого ресурса . Код, использующий другие ресурсы, может работать полностью независимо.

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

7 голосов
/ 06 февраля 2010

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

2 голосов
/ 06 февраля 2010

Да, переключение контекста может определенно произойти. Именно поэтому при доступе к общему ресурсу важно также заблокировать его из другого потока. Когда поток A заблокирован, поток B не может получить доступ к заблокированному коду.

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

1. lock(l);
2. -- change shared resource S here --
3. unlock(l);

Переключение контекста может произойти после шага 1, но другой поток не может удерживать блокировку в это время и, следовательно, не может изменить общий ресурс. Если доступ к общему ресурсу в одном из потоков осуществляется без блокировки - могут случиться плохие вещи!

Что касается расточительности, да, это расточительный метод. Вот почему существуют методы, которые пытаются вообще избежать блокировок. Эти методы называются без блокировки , и некоторые из них основаны на службах сильной блокировки, таких как CAS (Сравнение и замена) или другие.

0 голосов
/ 17 сентября 2011

Нет, это не очень дорого. Обычно есть только две возможности:

1) Система может выполнять и другие функции: В этом случае система все еще выполняет полезную работу со всеми доступными ядрами.

2) Системе больше нечего делать: В этом случае будет запланирован поток, который удерживает блокировку. Разумная система не оставит ядро ​​неиспользованным, пока есть готовый к запуску поток, который не запланирован.

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

...