Руководство по Ada (Ada 2022)
9.10 Общие переменные
Статическая семантика
Если два разных объекта, включая непересекающиеся части одного объекта, независимо адресуемы, они могут быть одновременны обрабатываться двумя разными логическими потоками управления без синхронизации, если оба не являются подкомпонентами одного полного объекта доступа, и хотя бы один из них не является атомным (см. C.6). Любые два непересекающихся объекта независимо адресуемы, если любой из объектов указан как независимо адресуемый (см. C.6). В противном случае два непересекающихся объекта независимо адресуемы, за исключением случаев, когда оба являются частями составного объекта, для которого задано несоответствующее значение для любого из следующих аспектов представления: (запись) Макет, Размер_компонента, Упаковка, Атомный или Конвенция; в этом случае неявно, являются ли части независимо адресуемыми.
Динамическая семантика
Отдельные логические потоки управления обычно выполняются независимо и параллельно друг с другом. Однако взаимодействия задач могут быть использованы для синхронизации действий двух или более логических потоков управления, чтобы, например, обеспечить осмысленное общение путем прямого обновления и чтения переменных, общих для них. Действия двух разных логических потоков управления синхронизируются в этом смысле, когда действие одного сигнализирует действие другого; действие A1 определено как сигнализирующее действие A2 при следующих обстоятельствах:
- Если A1 и A2 являются частью выполнения одной задачи, и правила языка требуют, чтобы A1 выполнялось перед A2;
- Если A1 является действием активатора, который инициирует активацию задачи, а A2 является частью выполнения активированной задачи;
- Если A1 является частью активации задачи, а A2 является действием ожидания завершения активации;
- Если A1 является частью выполнения задачи, а A2 является действием ожидания завершения задачи;
- Если A1 является завершением задачи T, а A2 — либо вычисление выражения T'Terminated, которое дает True, либо вызов Ada.Task_Identification.Is_Terminated с фактическим параметром, идентифицирующим T, и результатом True (см. C.7.1);
- Если A1 является действием выдачи вызова входа, а A2 — частью соответствующего выполнения соответствующего entry_body или accept_statement;
- Если A1 является частью выполнения accept_statement или entry_body, а A2 — действием возврата из соответствующего вызова входа;
- Если A1 является частью выполнения тела защищенной процедуры или entry_body для данного защищенного объекта, а A2 — частью последующего выполнения entry_body для того же защищенного объекта;
- Если A1 сигнализирует о каком-либо действии, которое, в свою очередь, сигнализирует A2.
Действие A1 определено как потенциально сигнализирующее действие A2, если A1 сигнализирует A2, если действия A1 и A2 происходят в рамках выполнения одного логического потока управления, и правила языка допускают, что действие A1 предшествует действию A2, или если действие A1 потенциально сигнализирует о каком-либо действии, которое, в свою очередь, потенциально сигнализирует об A2.
Два действия определяются как последовательные, если верно одно из следующих утверждений:
- Одно действие сигнализирует другое;
- Оба действия происходят в рамках выполнения одного логического потока управления;
- Оба действия происходят в рамках защищенных действий над одним и тем же защищенным объектом, и, по крайней мере, одно из действий является частью вызова на эксклюзивную защищенную операцию защищенного объекта.
Аспект Атомный или аспект Атомные_компоненты также могут быть указаны для обеспечения последовательности определенных чтений и обновлений — см. C.6.
Два действия, которые не являются последовательными, определены как параллельные действия.
Два действия определены как конфликтные, если одно действие присваивает объекту, а другое действие читает или присваивает часть того же объекта (или смежного объекта, если два не независимо адресуемы). Действие, включающее вызов подпрограммы или входа, определено как потенциально конфликтное с другим действием, если аспект Глобальный (или аспект Global'Class в случае вызова диспетчеризации) вызываемой подпрограммы или входа такой, что конфликтное действие могло бы произойти во время выполнения вызова. Аналогично, два вызова считаются потенциально конфликтными, если каждый из них имеет аспекты Глобальный (или Global'Class в случае вызова диспетчеризации) такого рода, что конфликтные действия могли бы произойти во время выполнения вызовов. Наконец, два конфликтующих действия также считаются потенциально конфликтующими.
Синхронизированный объект — это объект типа задачи или защищенного типа, атомный объект (см. C.6), объект приостановки (см. D.10) или синхронная барьер (см. D.10.1). Операции над такими объектами обязательно последовательны друг с другом и, следовательно, никогда не считаются конфликтными.
Ошибка выполнения
Выполнение двух параллельных действий является ошибочным, если действия производят конфликтное использование общей переменной (или смежных переменных, которые не независимо адресуемы).