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 6

2 ответа:

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

C++98 ничего не говорил о потоках. Программы, написанные на языке C++98, но использующие потоки, не имеют значения, определенного в языке C++98. Конечно, для расширения потоков целесообразно предоставлять стабильные, частные локальные переменные потокам, и они обычно это делают. Но могут существовать потоки, для которых это не так: например, процессы, созданные vfork в некоторых системах Unix, в которых родитель и потомок будут выполняться в одном кадре стека, так как v в vfork означает, что адресное пространство не клонируется, и vfork также не перенаправляет новый процесс на другую функцию.

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

Но тут есть кое-что. C++ теперь имеет замыкания. Что делать, если два потока вызывают одно и то же замыкание? Тогда у вас есть два потоки, использующие одни и те же локальные переменные. Замыкание подобно объекту, а его захваченные локальные переменные подобны членам. Если два или более потоков вызывают одно и то же замыкание, то у вас есть де-факто многопоточный объект, члены которого (т. е. захваченные лексические переменные) являются общими.

Поток также может просто передать адрес своих локальных переменных другому потоку, тем самым вызывая их совместное использование.