C++ локальные переменные и потоки (не локальные потоки)
Каковы модели памяти C++98 и C++11 для локальных массивов и взаимодействий с потоками?
Я Не ссылаюсь на ключевое слово C++11 thread_local, которое относится к глобальным и статическим переменным.
Вместо этого я хотел бы выяснить, каково гарантированное поведение потоков для массивов, выделяемых во время компиляции. Под временем компиляции я подразумеваю " int array[100]", который отличается от выделения с помощью ключевого слова new [] . Я не имею в виду статические переменные.
Например, предположим, что у меня есть следующая структура / класс:
struct xyz { int array[100]; };
И следующая функция:
void fn(int x) {
xyz dog;
for(int i=0; i<100; ++i) { dog.array[i] = x; }
// do something else with dog.array, eg. call another function with dog as parameter
}
Безопасно ли вызывать fn () из нескольких потоков? Похоже, что модель памяти C++ такова: все локальные нестатические переменные и массивы размещаются в стеке, и каждый поток имеет свой собственный стек. Верно ли это (т. е. это официально входит в стандарт)?
2 ответа:
Такие переменные выделяются в стеке, и поскольку каждый поток имеет свой собственный стек,то совершенно безопасно использовать локальные массивы. Они не отличаются, например, от локальных
int
s.
C++98 ничего не говорил о потоках. Программы, написанные на языке C++98, но использующие потоки, не имеют значения, определенного в языке C++98. Конечно, для расширения потоков целесообразно предоставлять стабильные, частные локальные переменные потокам, и они обычно это делают. Но могут существовать потоки, для которых это не так: например, процессы, созданные
vfork
в некоторых системах Unix, в которых родитель и потомок будут выполняться в одном кадре стека, так какv
вvfork
означает, что адресное пространство не клонируется, иvfork
также не перенаправляет новый процесс на другую функцию.В C++11 есть поддержка потоковой передачи. Локальные переменные в отдельных цепочках активации в отдельных потоках C++11 не вмешиваются. Но если вы выйдете за пределы языка и вытащите
Но тут есть кое-что. C++ теперь имеет замыкания. Что делать, если два потока вызывают одно и то же замыкание? Тогда у вас есть два потоки, использующие одни и те же локальные переменные. Замыкание подобно объекту, а его захваченные локальные переменные подобны членам. Если два или более потоков вызывают одно и то же замыкание, то у вас есть де-факто многопоточный объект, члены которого (т. е. захваченные лексические переменные) являются общими.vfork
или что-нибудь похожее на него, то все ставки будут отменены, как и раньше.Поток также может просто передать адрес своих локальных переменных другому потоку, тем самым вызывая их совместное использование.