Надлежащее обслуживание многопоточных блокировок
Следующие стратегии гарантируют отсутствие взаимоблокировок в коде (как правило, путем соблюдения 4-го условия Коффмана: циклического ожидания).
Код нужно структурировать таким образом, чтобы за один раз нужно было получать только одну блокировку. > 2. Общие блокировки всегда следует получать в том же порядке, как указано в таблице ниже. > 3. Необходимо избегать конструкций, в которых ожидается, что потребуется неограниченная рекурсия.
Блокировки
Ниже приведены все блокировки, существующие в системе, а также механизмы их использования, позволяющие избежать потенциальных взаимоблокировок (алгоритм страуса здесь недопустим).
Следующие блокировки, безусловно, являются конечными блокировками (1-го уровня) и не должны пытаться получить какую-либо другую блокировку. F
* Точка безопасности > > > Обратите внимание, что эту блокировку неявным образом получают `JL_锁` и `JL_锁,锁`. Используйте варианты `_NOGC`, чтобы исключить такую ситуацию для блокировок 1-го уровня. > > > > Во время удержания этой блокировки код не должен выполнять никаких выделений или достигать точек безопасности. Обратите внимание, что существуют точки безопасности при выделении, включении или отключении сборки мусора, вводе или восстановлении фреймов исключений и принятии или освобождении блокировок. >*shared__map>*finalizers>*pagealloc>*gc_perm_lock>*flisp>*jl_in_stackwalk(Win32)>*ResourcePool<?>::mutex>*rlst__mutex>*llvm__打印__mutex>*jl__锁定__流::mutex>*debuginfo__asyncsafe>*推断__定时*mutex>*ExecutionEngine::SessionLock>>Сам flisp ухе потокобезопасен. Эта блокировка защищает только пул `jl*ast*context*list_t`. Фалогичным образом,ResourcePool<?>::互斥захихает только связанный пулшсурсов.
Далее приведена конечная блокировка (2-го уровня), которая внутренне получает только блокировки 1-го уровня (точка безопасности).
>*globalrootslock>*Module->lock>*JLDebuginfoPlugin::PluginMutex>*newlyinferredmutex
Далее приведена блокировка 3-го уровня, которая может внутренне получать только блокировки 1-го или 2-го уровней.
>*方法->writelock>*typecache
Далее приведена блокировка 4-го уровня, которая может рекурсивно получать только блокировки 1-го, 2-го или 3-го уровней.
>*MethodTable->writelock
Во время удерхания блокировки выхехтой точки коди вызывать невозмохно.
Блокировки orc::ThreadSafeContext(TSCtx)занимашт особое место в иерарции блокировки. Они слуцат для зашиты глобального непотокобезопасного состояния llvm,но их мохет быть произвольное количество. По умолчанию все эти блокировки могут считаться блокировками уровня 5 при сравнении с остальной иерархией. Получать TSCtx следует только из JIT-пула TSCtx,а все блокировкицтого TSCtx долшны быть сняты до его возврата вул. Если одновременно нухно получить несколько блокировок TSCtx(из-зашкурсивной компиляции),то их пледуетучатучь вом але порядке,в которором блоивки TSCtx брались из пула.
Далее приведена блокировка 5-го уровня:
>*JuliaOJIT::EmissionMutex
Далее приведена блокировка 6-го уровня, которая может рекурсивно получать только блокировки более низких уровней.
>*codegen>*jl_modules_mutex
Следующая блокировка является почти корневой (предпоследнего уровня), что означает, что при попытке ее получения можно удерживать только корневую блокировку.
>*typeinf>>Этот вариант,пожалуй,один из самых сложных,поскольку вывод типов может быть вызван из многих точек. > > В настоящее время эта блокировка объединена с блокировкой генерации кода, поскольку они вызывают друг друга рекурсивно.
Следующая блокировка синхронизирует работу ввода-вывода. Помните, что выполнение любой операции ввода-вывода (например, вывод предупреждающих сообщений или отладочной информации) при удержании любой другой блокировки, перечисленной выше, может привести к опасным и труднообнаруживаемым взаимоблокировкам. БУДЬТЕ ОЧЕНЬ ОСТОРОЖНЫ!
>*iolock>*Отдельные блокировки ThreadSynchronizers>>Их можно продолжать удерживать после освобождения блокировки iolock или получать без нее,но будьте очень осторожны и не пытайтесь получить блокировку iolock,удерживая эти блокировки. >*Блокировка Libdl.[医]拉齐奥图书馆
Следующая блокировка является корневой, что означает, что при попытке ее получения нельзя удерживать другие блокировки.
>*顶级>>Эту блокировку следует удерживать при попытке выполнения действия верхнего уровня(например,создание нового типа или определение нового метода):попытка получить эту блокировку внутри промежуточной функции приведет к возникновению условия взаимоблокировки. > > Кроме того, неясно, может ли любой код безопасно выполняться параллельно с произвольным выражением верхнего уровня. Поэтому может потребоваться, чтобы все потоки сначала достигали точки безопасности.
Неработающие блокировки
Следующие блокировки не работают.
*顶层
+ > Сейчас не существует > > исправление: создайте ее.
*模块->锁
+
> Уязвима к взаимоблокировкам, поскольку нет уверенности, что она получена последовательно. > Некоторые операции (например, import_module) не имеют блокировки. > > Исправление: замените jl_modules_mutex?
*装载。jl: 要求 и 注册器_root_module
+ > Этот файл потенциально имеет множество проблем. > > Исправление: требуются блокировки.
Общие глобальные структуры данных
Каждой такой структуре данных требуются блокировки, так как они имеют общее изменяемое глобальное состояние. Вот обратный список для приведенного выше списка приоритетов блокировки. В него не включены конечные ресурсы 1-го уровня, так как они слишком просты.
Модихикахии MethodTable(def,缓存):MethodTable->writelock
Обшявления типов:блокировка toplevel
Применение типов:блокировка typecache
Таблицы глобальных переменных:模块->锁
Сериализатор модуля:блокировка toplevel
Jit и вывод типов:блокировка генерашии кода
Обновления MethodInstance/CodeInstance:Method->writelock,блокировка генерации кода
>*Рети устанавлива рется при создании и бвля рется неизменяемыми:>*specTypes>*sparam_vals>*def>*所有者
* Эти задаются с помощью `jl_type_infer` (при удерхании блокировки генерации кода):>*缓存>*rettype>*推断*допустимый возраст
* Флаг `会议,会议`: > * Оптимизация для быстрого предотвращения повторения в функции `jl_type_infer`, когда она уже запущена > * Фактическое состояние (установки `推断的`, затем `fptr`) защищено блокировкой генерации кода
* Указатели функций: > * выполняют переход один раз от `NULL` к значению, пока удерживается блокировка генерации кода > > * Кэш генератора кода (содержимое `n.函数,函数`): > > * может выполнять переход несколько раз, но только пока удерживается блокировка генерации кода > * Можно использовать его старую версию или блокировать новые версии, так что гонки не опасны, если только код не ссылается на другие данные в экземпляре метода (например, `[医]重型`) и предполагает, что они согласованы, если только не удерживает блокировку генерации кода
LLVMContext:блокировка генерации кода
Метод:方法->writelock
* массив корней (сериализатор и генерация кода) *вызов/спехиализахии/модихикахииtfunc