Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Char b;






b = 1;

int y = b;

 

Для большего реализма я мог бы использовать раздельную компиляцию (каждого потока), чтобы гарантировать, что компилятор/оптимизатор не смогут избавиться от доступа к памяти, и просто проигнорировать переменные c и b, и напрямую проинициализировать x и y единицей. Чему могут равняться x и y? Согласно спецификации языка С++11 единственным корректным и очевидным ответом является следующий: 1 и 1. Причина, по которой это важно заключается в том, что если вы возьмете обычный хороший компилятор С или С++ домногопоточной эры, то возможными ответами на предыдущий вопрос могут быть: 0 и 0 (маловероятно), 1 и 0, 0 и 1, и 1 и 1. И такое поведение происходило на практике. Как? Линковщик мог выделить память для c и b рядом друг с другом (в том же слове) и ничего в стандартах С и С++ 90-х годов не говорили о том, что так делать нельзя. В этом вопросе С++ похож на другие языки, разработанные без учета параллелизма. Однако, большинство современных процессоров не могут читать и писать по одному символу, они должны прочитать или записать целое слово, так что присваивание переменной c на самом деле выглядит так: «прочитать слово, в котором содержится с, заменить часть, которая содержит с и записать слово целиком назад». Поскольку присваивание b аналогично, то существует масса возможностей для двух потоков помешать друг другу, даже если ни один из потоков (согласно исходному тексту) не использует общие данные!

Итак, С++11 гарантирует, что такое невозможно для «разных ячеек памяти». Если быть более точным, то помимо операций чтения ячейка памяти не может использоваться двумя потоками без некоторой формы блокировки. Обратите внимание, что разные битовые поля внутри одного слова не являются разными ячейками памяти, поэтому структуры с битовыми полями не следует раздельно использовать между потоками без некоторой формы блокировки. Если не вдаваться в детали, то модель памяти в С++ именно «наиболее ожидаемая».

Однако, низкоуровневые проблемы многопоточности не всегда очевидны. Давайте рассмотрим пример:

// изначально x==0 и y==0

if (x) y = 1; // Поток 1

if (y) x = 1; // Поток 2

 

Если ли проблема с этим кодом? А если точнее, есть ли здесь гонка (data race)? (Нет, ее нет).

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



См. также:

  • Standard: 1.7 The C++ memory model [intro.memory]
  • Paul E. McKenney, Hans-J. Boehm, and Lawrence Crowl: C++ Data-Dependency Ordering: Atomics and Memory Model. N2556==08-0066.
  • Hans-J. Boehm: Threads basics, HPL technical report 2009-259. ``what every programmer should know about memory model issues.''
  • Hans-J. Boehm and Paul McKenney: A slightly dated FAQ on C++ memory model issues.

 

Потоки

Поток (thread) – это способ представления исполнения/вычисления в программе. В С++11, как и в большинстве современных языков, поток может (и обычно так и делает) разделять адресное пространство других потоков. В этом он отличается от процессов (process), который обычно не разделяет данные с другими процессами. С++ в прошлом неоднократно применялся для реализации потоков для многих аппаратных платформ и операционных систем, новшество же заключается в появлении потоков в стандартной библиотеке.

О многопоточности, параллелизме и конкрурентности написано множество толстых книг и десятки тысяч статей, в этом FAQ дается лишь краткий обзор. Четко понимать понятие многопоточности сложно. Если вы хотите заниматься параллельным программированием, как минимум прочитайте книгу. Не рассчитывайте только лишь на руководства, стандарт или FAQ.

Запуск потока осуществляется путем создания объекта std:: thread, в который передается функция или функтор (включая лямбда-выражение):

#include < thread>






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.