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

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

Листинг 4.2.Интерфейс класса std::queue

template >

class queue {

public:

explicit queue(const Container&);

explicit queue(Container&& = Container());

template explicit queue(const Alloc&);

template queue(const Container&, const Alloc&);

template queue(Container&&, const Alloc&);

template queue(queue&&, const Alloc&);

void swap(queue& q);

bool empty() const;

size_type size() const;

T& front();

const T& front() const;

T& back();

const T& back() const;

void push(const T& x);

void push(T&& x);

void pop();

template void emplace(Args&&... args);

};

Если не обращать внимания на конструирование, присваивание и обмен, то останется три группы операций: опрос состояния очереди в целом ( empty()и size()), опрос элементов очереди ( front()и back()) модификация очереди ( push(), pop()и emplace()). Ситуация аналогична той, что мы видели в разделе 3.2.3 для стека, поэтому возникают те же — внутренне присущие интерфейсу — проблемы с гонкой. Следовательно, front()и pop()необходимо объединить в одной функции — точно так же, как мы постудили с top()и pop()в случае стека. Но в коде в листинге 4.1 есть дополнительный нюанс: если очередь используется для передачи данных между потоками, то поток-получатель часто будет ожидать поступления данных. Поэтому включим два варианта pop(): try_pop()пытается извлечь значение из очереди, но сразу возвращает управление (с указанием ошибки), если в очереди ничего не было, a wait_and_pop()ждет, когда появятся данные. Взяв за образец сигнатуры функций из примера стека, представим интерфейс в следующем виде:

Листинг 4.3.Интерфейс класса threadsafe_queue

#include

template

class threadsafe_queue {

public:

threadsafe_queue();

threadsafe_queue(const threadsafe_queue&);

threadsafe_queue& operator=(

const threadsafe_queue&) = delete; ←┐ Для простоты

void push(T new_value); │ запрещаем присваивание

bool try_pop(T& value); ← (1)

std::shared_ptr try_pop(); ← (2)

void wait_and_pop(T& value);

std::shared_ptr wait_and_pop();

bool empty() const;

};

Как и в случае стека, мы для простоты уменьшили число конструкторов и запретили присваивание. И, как и раньше, предлагаем по два варианта функций try_pop()и wait_for_pop(). Первый перегруженный вариант try_pop() (1)сохраняет извлеченное значение в переданной по ссылке переменной, а возвращаемое значение использует для индикации ошибки: оно равно true, если значение получено, и false— в противном случае (см. раздел А.2). Во втором перегруженном варианте (2)так поступить нельзя, потому что возвращаемое значение — это данные, извлеченные из очереди. Однако же можно возвращать указатель NULL, если в очереди ничего не оказалось.

Ну и как же всё это соотносится с листингом 4.1? В следующем листинге показано, как перенести оттуда код в методы push()и wait_and_pop().

Листинг 4.4.Реализация функций push()и wait_and_pop()на основе кода из листинга 4.1

#include

#include

#include

template

class threadsafe_queue {

private:

std::mutex mut;

std::queue data_queue;

std::condition_variable data_cond;

public:

void push(T new_value) {

std::lock_guard lk(mut);

data_queue.push(new_value);

data_cond.notify_one();

}

void wait_and_pop(T& value) {

std::unique_lock lk(mut);

data_cond.wait(lk, [this]{return !data_queue.empty();});

value = data_queue.front();

data_queue.pop();

}

};

threadsafe_queue data_queue; ← (1)

void data_preparation_thread() {

while (more_data_to_prepare()) {

data_chunk const data = prepare_data();

data_queue.push(data); ← (2)

}

}

void data_processing_thread() {

while (true) {

data_chunk data;

data_queue.wait_and_pop(data); ← (3)

process(data);

if (is_last_chunk(data))

break;

}

}

Теперь мьютекс и условная переменная находятся в экземпляре threadsafe_queue, поэтому не нужно ни отдельных переменных (1), ни внешней синхронизации при обращении к функции push() (2). Кроме того, wait_and_pop()берет на себя заботу об ожидании условной переменной (3).

Второй перегруженный вариант wait_and_pop()тривиален, а остальные функции можно почти без изменений скопировать из кода стека в листинге 3.5. Ниже приведена окончательная реализация.

Листинг 4.5. Полное определение класса потокобезопасной очереди на базе условных переменных

#include

#include

#include

#include

template

class threadsafe_queue {

private:

mutable std::mutex mut;← (1) Мьютекс должен быть изменяемым

std::queue data_queue;

std::condition_variable data_cond;

public:

threadsafe_queue() {}

threadsafe_queue(threadsafe_queue const& other) {

std::lock_guard lk(other.mut);

data_queue = other.data_queue;

}

void push(T new_value) {

std::lock_guard lk(mut);

data_queue.push(new_value);

data_cond.notify_one();

}

void wait_and_pop(T& value) {

std::unique_lock lk(mut);

data_cond.wait(lk, [this]{ return !data_queue.empty(); });

value = data_queue.front();

data_queue.pop();

}

std::shared_ptr wait_and_pop() {

std::unique_lock lk(mut);

data_cond.wait(lk, [this]{ return !data_queue.empty(); });

std::shared_ptr

res(std::make_shared(data_queue.front()));

data_queue.pop();

return res;

}

bool try_pop(T& value) {

std::lock_guard lk(mut);

if (data_queue.empty())

return false;

value = data_queue.front();

data_queue.pop();

return true;

}

std::shared_ptr try_pop() {

std::lock_guard lk(mut);

if (data_queue.empty())

return std::shared_ptr();

std::shared_ptr

res(std::make_shared(data_queue.front()));

data_queue.pop();

return res;

}

bool empty() const {

std::lock_guard lk(mut);

return data_queue.empty();

}

};

Хотя empty()— константная функция-член, а параметр копирующего конструктора — const-ссылка, другие потоки могут хранить неконстантные ссылки на объект и вызывать изменяющие функции-члены, которые захватывают мьютекс. Поэтому захват мьютекса — это изменяющая операция, следовательно, член mutнеобходимо пометить как mutable (1), чтобы его можно было захватить в функции empty()и в копирующем конструкторе.

Условные переменные полезны и тогда, когда есть несколько потоков, ожидающих одного события. Если потоки используются для разделения работы и, следовательно, на извещение должен реагировать только один поток, то применима точно такая же структура программы, как в листинге 4.1; нужно только запустить несколько потоков обработки данных. При поступлении новых данных функция notify_one()разбудит только один поток, который проверяет условие внутри wait(), и этот единственный поток вернет управление из wait()(в ответ на помещение нового элемента в очередь data_queue). Заранее нельзя сказать, какой поток получит извещение и есть ли вообще ожидающие потоки (не исключено, что все они заняты обработкой ранее поступивших данных).

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

Интервал:

Закладка:

Сделать


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

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




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


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


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

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