Олег Цилюрик - QNX/UNIX - Анатомия параллелизма

Здесь есть возможность читать онлайн «Олег Цилюрик - QNX/UNIX - Анатомия параллелизма» — ознакомительный отрывок электронной книги совершенно бесплатно, а после прочтения отрывка купить полную версию. В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Город: Санкт-Петербург, Год выпуска: 2006, ISBN: 2006, Издательство: Символ-Плюс, Жанр: Программирование, ОС и Сети, на русском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

QNX/UNIX: Анатомия параллелизма: краткое содержание, описание и аннотация

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

Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.

QNX/UNIX: Анатомия параллелизма — читать онлайн ознакомительный отрывок

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

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

Интервал:

Закладка:

Сделать

atomic_sub() atomic_sub_value()

atomic_clr() atomic_clr_value()

atomic_set() atomic_set_value()

atomic_toggle() atomic_toggle_value()

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

// глобальные описания, доступные всем потокам

const unsigned int N = ...

uint8_t buf[N];

// индекс текущей позиции записи

unsigned int ind = 0;

// общий мьютекс, доступный каждому из потоков

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

...

// выполняется в каждом из потоков:

uint8_t res[M]; // результат некоторой операции

unsigned int how = ... // реальная длина этого результата

pthread_mutex_lock(&mutex);

memcpy((void*)buf + ind, (void*)res, how);

ind += how;

pthread_mutex_unlock(&mutex);

Используя атомарные операции, мы можем этот процесс записать так (все глобальные описания остаются неизменными):

// глобальные описания, доступные всем потокам

...

// индекс текущей позиции записи

volatile unsigned int ind = 0;

...

// выполняется в каждом из потоков:

uint8_t res[M]; // результат некоторой операции

unsigned int how = ... // реальная длина этого результата

memcpy((void*)buf + atomic_add_value(ind, how), (void*)res, how);

Или даже так:

// глобальные описания, доступные всем потокам

...

// указательтекущей позиции записи:

volatile unsigned int ind = (unsigned int)buf;

...

// выполняется в каждом из потоков:

memcpy((void*)atomic_add_value(ind, how), (void*)res, how);

В последнем случае это, конечно, трюкачество, построенное на том, что в 32-разрядной архитектуре представления указателя и переменной unsigned intсовпадают, но это «работающее трюкачество» и работающее иногда весьма эффективно.

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

cout << "Это вывод потока " << pthread_self() << endl;

Но так делать нельзя: при таком решении у нас появляются 2 проблемы, одна из которых очевидна, а другая — не очень:

1. Выводы разных потоков могут «смешиваться»; более того, за счет буферизации вывода некоторые «рваные» фрагменты мы будем наблюдать дважды. Одним словом, наш вывод окажется полностью «нечитабельным».

2. При осуществлении вывода в контексте потока почти наверняка в процессе вывода будут выполняться системные вызовы, которые потребуют новой диспетчеризации и приведут к вытеснению исходного потока. При этом порядок передачи управления от потока к потоку при наличии отладочного вывода будет отличаться от порядка при его отсутствии. А это, наверное, не совсем то, что мы ожидали. В результате при наличии отладочного вывода мы можем наблюдать совсем не ту картину, для изучения которой этот вывод, собственно, и предназначен.

Эти эффекты не связаны с какой-то конкретной формой вывода, такой как вывод в поток, показанный выше; точно так же будет вести себя и традиционный вызов printf(...).

Проблема очень просто решается, если вместо непосредственного вывода из потоков последовательно сбрасывать все сообщения в промежуточный буфер, который будет выводиться в те периоды времени программы, когда запись в него не производится:

const int N = ... , M = ...;

char buf[N];

volatile unsigned ind = 0;

...

// а вот это производится из каждого потока

char tbuf[M];

sprintf(tbuf, "Это вывод потока %X", pthread_self());

strcpy(buf + atomic_add_value(ind, strlen(tbuf)), tbuf);

И наконец, последнее: есть ли смысл во введении этого дополнительного механизма, если всегда существует альтернативная форма организации такой же защиты доступа посредством критической секции (например, при использовании мьютекса)? Сравним ( файл a1.cc ) временные затраты при многократном изменении значения переменной для случаев атомарных операций и критической секции на базе мьютекса (мы берем именно мьютекс, потому что из всех примитивов синхронизации он самый низкоуровневый и быстрый):

Сравнение мьютекса и двух форм вызова атомарной операции

#include

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

Интервал:

Закладка:

Сделать

Похожие книги на «QNX/UNIX: Анатомия параллелизма»

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


Отзывы о книге «QNX/UNIX: Анатомия параллелизма»

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

x