Энтони Уильямс - Параллельное программирование на С++ в действии. Практика разработки многопоточных программ

Тут можно читать онлайн Энтони Уильямс - Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, издательство ДМК Пресс, год 2012. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Параллельное программирование на С++ в действии. Практика разработки многопоточных программ
  • Автор:
  • Жанр:
  • Издательство:
    ДМК Пресс
  • Год:
    2012
  • Город:
    Москва
  • ISBN:
    978-5-94074-448-1
  • Рейтинг:
    5/5. Голосов: 11
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 100
    • 1
    • 2
    • 3
    • 4
    • 5

Энтони Уильямс - Параллельное программирование на С++ в действии. Практика разработки многопоточных программ краткое содержание

Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - описание и краткое содержание, автор Энтони Уильямс, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru
В наши дни компьютеры с несколькими многоядерными процессорами стали нормой. Стандарт С++11 языка С++ предоставляет развитую поддержку многопоточности в приложениях. Поэтому, чтобы сохранять конкурентоспособность, вы должны овладеть принципами и приемами их разработки, а также новыми средствами языка, относящимися к параллелизму.
Книга «Параллельное программирование на С++ в действии» не предполагает предварительных знаний в этой области. Вдумчиво читая ее, вы научитесь писать надежные и элегантные многопоточные программы на С++11. Вы узнаете о том, что такое потоковая модель памяти, и о том, какие средства поддержки многопоточности, в том числе запуска и синхронизации потоков, имеются в стандартной библиотеке. Попутно вы познакомитесь с различными нетривиальными проблемами программирования в условиях параллелизма.

Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - читать онлайн бесплатно полную версию (весь текст целиком)

Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - читать книгу онлайн бесплатно, автор Энтони Уильямс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

std::atomic b(true);

b = false;

Что касается оператора присваивания с неатомарным boolв правой части, нужно еще отметить отход от общепринятого соглашения о возврате ссылки на объект в левой части — этот оператор возвращает присвоенное значение типа bool. Такая практика обычна для атомарных типов: все поддерживаемые ими операторы присваивания возвращают значения (соответствующего неатомарного типа), а не ссылки. Если бы возвращалась ссылка на атомарную переменную, то программа, которой нужен результат присваивания, должна была бы явно загрузить значение, открывая возможность для модификации результата другим потоком в промежутке между присваиванием и чтением. Получая же результат присваивания в виде неатомарного значения, мы обходимся без дополнительной операции загрузки и можем быть уверены, что получено именно то значение, которое было сохранено.

Запись (любого значения: trueили false) производится не чрезмерно ограничительной функцией clear()из класса std::atomic_flag, а путём вызова функции-члена store(), хотя семантику упорядочения доступа к памяти по-прежнему можно задать. Аналогично вместо test_and_set()используется более общая функция-член exchange(), которая позволяет атомарно заменить ранее сохраненное значение новым и вернуть прежнее значение. Тип std::atomicподдерживает также проверку значения без модификации посредством неявного преобразования к типу boolили явного обращения к функции load(). Как нетрудно догадаться, store()— это операция сохранения, load()— операция загрузки, a exchange()— операция чтения-модификации-записи:

std::atomic b;

bool x = b.load(std::memory_order_acquire);

b.store(true);

x = b.exchange(false, std::memory_order_acq_rel);

Функция exchange()— не единственная операция чтения-модификации-записи, которую поддерживает тип std::atomic; в нем также определена операция сохранения нового значения, если текущее совпадает с ожидаемым.

Сохранение (или несохранение) нового значения в зависимости от текущего

Новая операция называется «сравнить и обменять» и реализована в виде функций-членов compare_exchange_weak()и compare_exchange_strong(). Эта операция — краеугольный камень программирования с использованием атомарных типов; она сравнивает значение атомарной переменной с указанным ожидаемым значением и, если они совпадают, то сохраняет указанное новое значение. Если же значения не совпадают, то ожидаемое значение заменяется фактическим значением атомарной переменной. Функции сравнения и обмена возвращают значение типа bool, равное true, если сохранение было произведено, и false— в противном случае.

В случае compare_exchange_weak()сохранение может не произойти, даже если текущее значение совпадает с ожидаемым. В таком случае значение переменной не изменится, а функция вернет false. Такое возможно на машинах, не имеющих аппаратной команды сравнить-и-обменять, если процессор не может гарантировать атомарности операции — например, потому что поток, в котором операция выполнялась, был переключён в середине требуемой последовательности команд и замещен другим потоком (когда потоков больше, чем процессоров). Эта ситуация называется ложным отказом , потому что причиной отказа являются не значения переменных, а хронометраж выполнения функции.

Поскольку compare_exchange_weak()может стать жертвой ложного отказа, обычно ее вызывают в цикле:

bool expected = false;

extern atomic b; // установлена где-то в другом месте

while (!b.compare_exchange_weak(expected, true) && !expected);

Этот цикл продолжается, пока expectedравно false, что указывает на ложный отказ compare_exchange_weak().

С другой стороны, compare_exchange_strong()гарантированно возвращает falseтолько в том случае, когда текущее значение не было равно ожидаемому ( expected). Это устраняет необходимость в показанном выше цикле, когда нужно только узнать, удалось ли нам изменить переменную или другой поток добрался до нее раньше.

Если мы хотим изменить переменную, каким бы ни было ее текущее значение (при этом новое значение может зависеть от текущего), то обновление expectedоказывается полезной штукой; на каждой итерации цикла expectedперезагружается, так что если другой поток не модифицирует значение в промежутке, то вызов compare_exchange_weak()или compare_exchange_strong()должен оказаться успешным на следующей итерации. Если новое сохраняемое значение вычисляется просто, то выгоднее использовать compare_exchange_weak(), чтобы избежать двойного цикла на платформах, где compare_exchange_weak() может давать ложный отказ (и, следовательно, compare_exchange_strong()содержит цикл). С другой стороны, если вычисление нового значения занимает длительное время, то имеет смысл использовать compare_exchange_strong(), чтобы не вычислять значение заново, когда expectedне изменилась. Для типа std::atomicэто не столь существенно — в конце концов, есть всего два возможных значения — но для более широких атомарных типов различие может оказаться заметным.

Функции сравнения и обмена необычны еще и тем, что могут принимать два параметра упорядочения доступа к памяти. Это позволяет по-разному задавать семантику упорядочения в случае успеха и отказа; быть может, при успешном вызове требуется семантика memory_order_acq_rel, а при неудачном — memory_order_relaxed. В случае отказа функция сохранить-и-обменять не производит сохранение, поэтому семантика memory_order_releaseили memory_order_acq_relнеприменима. Поэтому задавать эти варианты упорядочения для отказа не разрешается. Кроме того, нельзя задавать для отказа более строгое упорядочение, чем для успеха; если вы требуете семантику memory_order_acquireили memory_order_seq_cstв случае отказа, то должны потребовать такую же и в случае успеха.

Если упорядочение для отказа не задано, то предполагается, что оно такое же, как для успеха, с тем отличием, что часть release заменяется: memory_order_releaseстановится memory_order_relaxed, a memory_order_acq_relmemory_order_acquire. Если не задано ни одно упорядочение, то как обычно предполагается memory_order_seq_cst, то есть полное последовательное упорядочение доступа как в случае успеха, так и в случае отказа. Следующие два вызова compare_exchange_weak()эквивалентны:

std::atomic b;

bool expected;

b.compare_exchange_weak(expected, true,

memory_order_acq_rel, memory_order_acquire);

b.compare_exchange_weak(expected, true, memory_order_acq_rel);

К чему приводит задание того или иного упорядочения, я расскажу в разделе 5.3.

Еще одно отличие std::atomicот std::atomic_flagзаключается в том, что тип std::atomicне обязательно свободен от блокировок; для обеспечения атомарности реализация библиотеки может захватывать внутренний мьютекс. В тех редких случаях, когда это важно, можно с помощью функции-члена is_lock_free()узнать, являются ли операции над std::atomicсвободными от блокировок. Это еще одна особенность, присущая всем атомарным типам, кроме std::atomic_flag.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Энтони Уильямс читать все книги автора по порядку

Энтони Уильямс - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Параллельное программирование на С++ в действии. Практика разработки многопоточных программ отзывы


Отзывы читателей о книге Параллельное программирование на С++ в действии. Практика разработки многопоточных программ, автор: Энтони Уильямс. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x