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

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

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

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

Интервал:

Закладка:

Сделать
Ослабленное упорядочение

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

Чтобы продемонстрировать, до какой степени могут быть «ослаблены» операции в этой модели, достаточно всего двух потоков (см. листинг 5.5).

Листинг 5.5.К ослабленным операциям предъявляются очень слабые требования

#include

#include

#include

std::atomic x,y;

std::atomic z;

void write_x_then_y() {

x.store(true, std::memory_order_relaxed); ← (1)

y.store(true, std::memory_order_relaxed); ← (2)

}

void read_y_then_x() {

while (!y.load(std::memory_order_relaxed));← (3)

if (x.load(std::memory_order_relaxed)) ← (4)

++z;

}

int main() {

x = false;

y = false;

z = 0;

std::thread а(write_x_then_y);

std::thread b(read_y_then_x);

a.join();

b.join();

assert (z.load() != 0); ← (5)

}

На этот раз утверждение (5) может сработать, потому что операция загрузки x (4)может прочитать false, даже если загрузка y (3)прочитает true, а сохранение x (1)происходит-раньше сохранения y (2). xи y— разные переменные, поэтому нет никаких гарантий относительно порядка видимости результатов операций над каждой из них.

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

Рис 54Ослабленные атомарные операции и отношения происходитраньше - фото 12

Рис. 5.4.Ослабленные атомарные операции и отношения происходит-раньше

Рассмотрим чуть более сложный пример с тремя переменными и пятью потоками.

Листинг 5.6.Ослабленные операции в нескольких потоках

#include

#include

#include

std::atomic x(0), y(0), z(0);← (1)

std::atomic go(false); ← (2)

unsigned const loop_count = 10;

struct read_values {

int x, y, z;

};

read_values values1[loop_count];

read_values values2[loop_count];

read_values values3[loop_count];

read_values values4[loop_count];

read_values values5[loop_count];

void increment(

std::atomic* var_to_inc, read_values* values) {

while (!go) ← (3) В цикле ждем сигнала

std::this_thread::yield();

for (unsigned i = 0; i < loop_count; ++i) {

values[i].x = x.load(std::memory_order_relaxed);

values[i].y = y.load(std::memory_order_relaxed);

values[i].z = z.load(std::memory_order_relaxed);

var_to_inc->store(i + 1, std::memory_order_relaxed);← (4)

std::this_thread::yield();

}

}

void read_vals(read_values* values) {

while (!go) ← (5) В цикле ждем сигнала

std::this_thread::yield();

for (unsigned i = 0; i < loop_count; ++i) {

values[i].x = x.load(std::memory_order_relaxed);

values[i].y = y.load(std::memory_order_relaxed);

values[i].z = z.load(std::memory_order_relaxed);

std::this_thread::yield();

}

}

void print(read_values* v) {

for (unsigned i = 0; i < loop_count; ++i) {

if (i)

std::cout << ",";

std::cout <<

"(" << v [i] .x << "," << v[i].y << "," << v[i].z << ")";

}

std::cout << std::endl;

}

int main() {

std::thread t1(increment, &x, values1);

std::thread t2(increment, &y, values2);

std::thread t3(increment, &z, values3);

std::thread t4(read_vals, values4);

std::thread t5(read_vals, values5);

go = true; ←┐ Сигнал к началу выполнения

(6) главного цикла

t5.join();

t4.join();

t3.join();

t2.join();

t1.join();

print(values1);←┐

print(values2); │ Печатаем получившиеся

print(values3); (7) значения

print(values4);

print(values5);

}

По существу, это очень простая программа. У нас есть три разделяемых глобальных атомарных переменных (1)и пять потоков. Каждый поток выполняет 10 итераций цикла, читая значения трех атомарных переменных в режиме memory_order_relaxedи сохраняя их в массиве. Три из пяти потоков обновляют одну из атомарных переменных при каждом проходе по циклу (4), а остальные два только читают ее. После присоединения всех потоков мы распечатываем массивы, заполненные каждым из них (7).

Атомарная переменная go (2)служит для того, чтобы все потоки начали работу по возможности одновременно. Запуск потока — накладная операция и, не будь явной задержки, первый поток мог бы завершиться еще до того, как последний зачал работать. Каждый поток ждет, пока переменная goстанет равна true, и только потом входит в главный цикл (3), (5), а переменная goустанавливается в trueтолько после запуска всех потоков (6).

Ниже показан один из возможных результатов прогона этой прогона:

(0,0,0),(1,0,0),(2,0,0),(3,0,0),(4,0,0),(5,7,0),(6,7,8),(7,9,8),(8,9,8),(9,9,10)

(0,0,0),(0,1,0),(0,2,0),(1,3,5),(8,4,5),(8,5,5),(8,6,6),(8,7,9),(10,8,9),(10,9,10)

(0,0,0),(0,0,1),(0,0,2),(0,0,3),(0,0,4),(0,0,5),(0,0,6),(0,0,7),(0,0,8),(0,0,9)

(1,3,0),(2,3,0),(2,4,1),(3,6,4),(3,9,5),(5,10,6),(5,10,8),(5,10,10),(9,10,10),(10,10,10)

(0,0,0),(0,0,0),(0,0,0),(6,3,7),(6,5,7),(7,7,7),(7,8,7),(8,8,7),(8,8,9),(8,8,9)

Первые три строки относятся к потокам, выполнявшим обновление, последние две — к потокам, которые занимались только чтением. Каждая тройка — это значения переменных x, y, zв порядке итераций цикла. Следует отметить несколько моментов.

• В первом наборе значения xувеличиваются на 1 в каждой тройке, во втором наборе на 1 увеличиваются значения y, а в третьем — значения z.

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

Интервал:

Закладка:

Сделать


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

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




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


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


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

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