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

Здесь есть возможность читать онлайн «Энтони Уильямс - Параллельное программирование на С++ в действии. Практика разработки многопоточных программ» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Город: Москва, Год выпуска: 2012, ISBN: 2012, Издательство: ДМК Пресс, Жанр: Программирование, на русском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

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

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Параллельное программирование на С++ в действии. Практика разработки многопоточных программ»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

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

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

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Параллельное программирование на С++ в действии. Практика разработки многопоточных программ», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

std::unique_ptr const old_head = std::move(head);

head = std::move(old_head->next);← (3)

return res;

}

void push(T new_value) {

std::unique_ptr p(new node(std::move(new_value)));

node* const new_tail = p.get();

if (tail) {

tail->next = std::move(p);← (4)

} else {

head = std::move(p); ← (5)

}

tail = new_tail; ← (6)

}

};

Прежде всего отметим, что в листинге 6.4 для управления узлами используется класс std::unique_ptr, потому что он гарантирует удаление потерявших актуальность узлов (и содержащихся в них данных) без явного использования delete. За передачу владения отвечает head, тогда как tailявляется простым указателем на последний узел.

В однопоточном контексте эта реализация прекрасно работает, но при попытке ввести мелкогранулярные блокировки в многопоточном контексте возникают две проблемы. Учитывая наличие двух элементов данных ( head (1)и tail (2)), мы в принципе могли бы использовать два мьютекса — для защиты headи tailсоответственно. Но не всё так просто.

Самая очевидная проблема заключается в том, что push()может изменять как head (5), так и tail (6), поэтому придётся захватывать оба мьютекса. Это не очень хорошо, но не трагедия, потому что захватить два мьютекса, конечно, можно. Настоящая проблема возникает из-за того, что и push(), и pop()обращаются к указателю nextв узле: push()обновляет tail->next (4), a try_pop()читает head->next (3). Если в очереди всего один элемент, то head==tail, и, значит, head->nextи tail->next— один и тот же объект, который, следовательно, нуждается в защите. Поскольку нельзя сказать, один это объект или нет, не прочитав и head, и tail, нам приходится захватывать один и тот же мьютекс в push()и в try_pop(), и получается, что мы ничего не выиграли по сравнению с предыдущей реализацией. Есть ли выход из этого тупика?

Обеспечение параллелизма за счет отделения данных

Решить проблему можно, заранее выделив фиктивный узел, не содержащий данных, и тем самым гарантировать, что в очереди всегда есть хотя бы один узел, отделяющий голову от хвоста. В случае пустой очереди headи tailтеперь указывают на фиктивный узел, а не равны NULL. Это хорошо, потому что try_pop()не обращается к head->next, если очередь пуста. После добавления в очередь узла (в результате чего в ней находится один реальный узел) headи tailуказывают на разные узлы, так что гонки за head->nextи tail->nextне возникает. Недостаток этого решения в том, что нам пришлось добавить лишний уровень косвенности для хранения указателя на данные, чтобы поддержать фиктивный узел. В следующем листинге показано, как теперь выглядит реализация.

Листинг 6.5.Простая очередь с фиктивным узлом

template

class queue {

private:

struct node {

std::shared_ptr data;← (1)

std::unique_ptr next;

};

std::unique_ptr head;

node* tail;

public:

queue():

head(new node), tail(head.get()) (2)

{}

queue(const queue& other) = delete;

queue& operator=(const queue& other) = delete;

std::shared_ptr try_pop() {

if (head.get() ==tail) (3)

{

return std::shared_ptr();

}

std::shared_ptr const res(head->data); (4)

std::unique_ptr old_head = std::move(head);

head = std::move(old_head->next); ← (5)

return res; ← (6)

}

void push(T new_value) {

std::shared_ptr new_data(

std::make_shared(std::move(new_value))); (7)

std::unique_ptr p(new node); (8)

tail->data = new_data; (9)

node* const new_tail = p.get();

tail->next = std::move(p);

tail = new_tail;

}

};

Изменения в try_pop()минимальны. Во-первых, мы сравниваем headс tail (3), а не с NULL, потому что благодаря наличию фиктивного узла headникогда не может обратиться в NULL. Поскольку headимеет тип std::unique_ptr, для сравнения необходимо вызывать head.get(). Во-вторых, так как в nodeтеперь хранится указатель на данные (1), то можно извлекать указатель непосредственно (4)без конструирования нового экземпляра T. Наиболее серьезные изменения претерпела функция push(): мы должны сначала создать новый экземпляр Tв куче и передать владение им std::shared_ptr<> (7)(обратите внимание на использование функции std::make_shared, чтобы избежать накладных расходов на второе выделение памяти под счетчик ссылок). Вновь созданный узел станет новым фиктивным узлом, поэтому передавать конструктору значение new_valueнеобязательно (8). Вместо этого мы записываем в старый фиктивный узел значение только что созданной копии — new_value (9). Наконец, первоначальный фиктивный узел следует создать в конструкторе (2).

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

Интервал:

Закладка:

Сделать

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

Представляем Вашему вниманию похожие книги на «Параллельное программирование на С++ в действии. Практика разработки многопоточных программ» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


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

Обсуждение, отзывы о книге «Параллельное программирование на С++ в действии. Практика разработки многопоточных программ» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x