Что гарантирует, что разные несвязанные объекты в двух несвязанных потоках не имеют (неизбежного) состояния гонки? - PullRequest
0 голосов
/ 29 мая 2019

Когда разные потоки используют только несвязанные объекты и буквально не делятся чем-либо, они не могут иметь расы, верно? Очевидно.

На самом деле все потоки имеют что-то общее: адресное пространство. Нет гарантии, что область памяти, которая использовалась одним потоком, не будет выделена в другое время другому потоку. Это может быть справедливо для памяти для динамически распределенных объектов или даже для автоматических объектов: не существует предписания, что пространство памяти для «стеков» (локальных объектов функций) нескольких потоков предварительно выделяется (даже лениво), не пересекается и представлен как обычный линейный «стек»; это может быть что угодно с поведением стека (FILO). Таким образом, область памяти, используемая для хранения автоматического объекта, может быть позже использована другим автоматическим объектом в другом потоке.

Это само по себе кажется довольно безобидным и неинтересным, поскольку то, как создается пространство для автоматических объектов, важно только при отсутствии места (очень большие автоматические массивы или глубокая рекурсия).

А как насчет синхронизации? Несвязанные непересекающиеся потоки, очевидно, не могут использовать какой-либо примитив синхронизации C ++ для обеспечения правильной синхронизации, так как по определению нет ничего (для) синхронизации (вкл), поэтому не происходит до того, как между потоками будет создано отношение .

Что, если реализация повторно использует диапазон памяти стека foo() (включая расположение i) после уничтожения локальных переменных и выхода из foo() в потоке 1, чтобы сохранить переменные для bar() в потоке 2

void foo() { // in thread 1
   int i;
   i = 1;
}

void bar() { // in thread 2
   int i;
   i = 2;
}

Не происходит до между i = 1 и i = 2.

Это может вызвать гонку данных и неопределенное поведение?

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

Ответы [ 2 ]

4 голосов
/ 29 мая 2019

Модель памяти C ++ не ведет себя так, как вы могли бы ожидать интуитивно. Например, он имеет ячейки памяти, но цитирует черновик N4713, раздел 6.6.1, пункт 3:

A ячейка памяти является либо объектом скалярного типа, либо максимальной последовательностью смежных битовых полей, все из которых имеют ненулевая ширина. [ Примечание: Различные функции языка, такие как ссылки и виртуальные функции, могут включать дополнительные области памяти, которые не доступны для программ, но управляются реализацией. - конец примечания ] Два или более потоков выполнения (6.8.2) могут получать доступ к отдельным ячейкам памяти без вмешательства друг с другом.

Таким образом, в модели памяти C ++ два разных объекта в разных потоках никогда не считаются имеющими одинаковое расположение в памяти, даже если на уровне физической машины один выделяется в одной и той же ОЗУ после освобождения другого.

В модели памяти C ++ ситуация, о которой вы спрашиваете, не является гонкой данных. Реализация должна предпринять все необходимые шаги для обеспечения безопасности, независимо от модели памяти оборудования.

2 голосов
/ 29 мая 2019

Физический компьютер "тот же адрес" не имеет отношения к модели памяти C ++. Модель памяти C ++ говорит о поведении абстрактной машины. Адреса в абстрактной машине могут быть несопоставимы фундаментальным образом, даже если они имеют один и тот же машинный адрес в разное время.

Условия гонки на абстрактной машине C ++ говорят об операциях в ней, а не на физической машине. Работа компилятора состоит в том, чтобы гарантировать, что реализация на абстрактной машине кода C ++ на физическом компьютере соответствует требованиям.

Если он делает странные вещи, такие как многократное использование адресного пространства стека между потоками, то он делает все, что должен, для того, чтобы поддерживать отсутствие условий гонки при доступе к несвязанным переменным в абстрактной машине. Ничего из этого не происходит на уровне кода C ++; здесь нет кода на C ++ (кроме, возможно, namespace std).

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