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

Тут можно читать онлайн Энтони Уильямс - Параллельное программирование на С++ в действии. Практика разработки многопоточных программ - бесплатно полную версию книги (целиком) без сокращений. Жанр: 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. Вы узнаете о том, что такое потоковая модель памяти, и о том, какие средства поддержки многопоточности, в том числе запуска и синхронизации потоков, имеются в стандартной библиотеке. Попутно вы познакомитесь с различными нетривиальными проблемами программирования в условиях параллелизма.

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

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

Интервал:

Закладка:

Сделать

Самый простой механизм защиты разделяемых данных из описанных в стандарте С++ — это мьютекс, с него мы и начнем рассмотрение.

3.2. Защита разделяемых данных с помощью мьютексов

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

Что ж, это вовсе не сказка — именно такое поведение вы получаете при использовании примитива синхронизации, который называется мьютекс (слово mutex происходит от mutual exclusion — взаимное исключение). Перед тем как обратиться к структуре данных, программа захватывает (lock) мьютекс, а по завершении операций с ней освобождает (unlock) его. Библиотека Thread Library гарантирует, что если один поток захватил некоторый мьютекс, то все остальные потоки, пытающиеся захватить тот же мьютекс, будут вынуждены ждать, пока удачливый конкурент не освободит его. В результате все потоки видят согласованное представление разделяемых данных, без нарушенных инвариантов.

Мьютексы — наиболее общий механизм защиты данных в С++, но панацеей они не являются; важно структурировать код так, чтобы защитить нужные данные (см. раздел 3.2.2), и избегать состояний гонки, внутренне присущих интерфейсам (см раздел 3.2.3). С мьютексами связаны и собственные проблемы, а именно: взаимоблокировки (deadlock) (см. раздел 3.2.4), а также защита слишком большого или слишком малого количества данных (см. раздел 3.2.8). Но начнем с простого.

3.2.1. Использование мьютексов в С++

В С++ для создания мьютекса следует сконструировать объект типа std::mutex, для захвата мьютекса служит функция-член lock(), а для освобождения — функция-член unlock(). Однако вызывать эти функции напрямую не рекомендуется, потому что в этом случае необходимо помнить о вызове unlock()на каждом пути выхода из функции, в том числе и вследствие исключений. Вместо этого в стандартной библиотеке имеется шаблон класса std::lock_guard, который реализует идиому RAII — захватывает мьютекс в конструкторе и освобождает в деструкторе, — гарантируя тем самым, что захваченный мьютекс обязательно будет освобожден. В листинге 3.1 показано, как с помощью классов std::mutexи std::lock_guardзащитить список, к которому могут обращаться несколько потоков. Оба класса определены в заголовке .

Листинг 3.1.Защита списка с помощью мьютекса

#include

#include

#include

std::list some_list; ← (1)

std::mutex some_mutex; ← (2)

void add_to_list(int new_value) {

std::lock_guard guard(some_mutex); ← (3)

some_list.push_back(new_value);

}

bool list_contains(int value_to_find) {

std::lock_guard guard(some_mutex); ← (4)

return

std::find(some_list.begin(), some_list.end(), value_to_find) !=

some_list.end();

}

В листинге 3.1 есть глобальный список (1), который защищен глобальным же объектом std::mutex (2). Вызов std::lock_guardв add_to_list() (3)и list_contains() (4)означает, что доступ к списку из этих двух функций является взаимно исключающим: list_contains()никогда не увидит промежуточного результата модификации списка, выполняемой в add_to_list().

Хотя иногда такое использование глобальных переменных уместно, в большинстве случаев мьютекс и защищаемые им данные помещают в один класс, а не в глобальные переменные. Это не что иное, как стандартное применение правил объектно-ориентированного проектирования; помещая обе сущности в класс, вы четко даете понять, что они взаимосвязаны, а, кроме того, обеспечиваете инкапсулирование функциональности и ограничение доступа. В данном случае функции add_to_listи list_containsследует сделать функциями-членами класса, а мьютекс и защищаемые им данные — закрытыми переменными-членами класса. Так будет гораздо проще понять, какой код имеет доступ к этим данным и, следовательно, в каких участках программы необходимо захватывать мьютекс. Если все функции-члены класса захватывают мьютекс перед обращением к каким-то другим данным-членам и освобождают по завершении действий, то данные оказываются надежно защищены от любопытствующих.

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

3.2.2. Структурирование кода для защиты разделяемых данных

Как мы только что видели, для защиты данных с помощью мьютекса недостаточно просто «воткнуть» объект std::lock_guardв каждую функцию-член: один-единственный «отбившийся» указатель или ссылка сводит всю защиту на нет. На некотором уровне проверить наличие таких отбившихся указателей легко — если ни одна функция-член не передает вызывающей программе указатель или ссылку на защищенные данные в виде возвращаемого значения или выходного параметра, то данные в безопасности. Но стоит копнуть чуть глубже, как выясняется, что всё не так просто, — а просто никогда не бывает. Недостаточно проверить, что функции-члены не возвращают указатели и ссылки вызывающей программе, нужно еще убедиться, что такие указатели и ссылки не передаются в виде входных параметров вызываемым ими функциям, которые вы не контролируете. Это ничуть не менее опасно — что, если такая функция сохранит где-то указатель или ссылку, а потом какой-то другой код обратится к данным, не захватив предварительно мьютекс? Особенно следует остерегаться функций, которые передаются во время выполнения в виде аргументов или иными способами, как показано в листинге 3.2.

Листинг 3.2.Непреднамеренная передача наружу ссылки на защищённые данные

class some_data {

int а;

std::string b;

public:

void do_something();

};

class data_wrapper {

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

Интервал:

Закладка:

Сделать


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

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




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


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


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

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