QNX/UNIX: Анатомия параллелизма
QNX/UNIX: Анатомия параллелизма читать книгу онлайн
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
# nice -n-19 a1 -n10000000 -a -v
all cycles - 441158981; on operation - 44
Условная переменная
Одним из важнейших принципов использования мьютексов является максимальное сокращение размеров критической секции, то есть участка, который потоки должны проходить последовательно. Однако зачастую возникает необходимость ожидания выполнения некоторого условия внутри критической секции.
Реализация подобного ожидания «в лоб» привела бы к тому, что все потоки, разделяющие данную критическую секцию, были бы вынуждены ждать выполнения условия для каждого из них. При «правильной» реализации ожидания поток должен освобождать мьютекс на время ожидания и вновь захватывать его, когда ожидаемое условие выполняется. Специально для этого случая стандартом POSIX предусмотрены условные переменные. QNX Neutrino реализует условные переменные как на уровне вызовов микроядра в своем native API, так и в соответствии со стандартом POSIX.
Отметим, что дополнение мьютекса условной переменной делает их комбинацию универсальным базисом, на котором могут быть построены любые сколь угодно сложные в своем поведении объекты синхронизации.
Фактически совместное использование мьютекса и условной переменной создает специфический комбинированный объект синхронизации, который может иметь принципиально более широкое применение, чем отдельно взятый мьютекс. Тем не менее поведение этого объекта синхронизации не столь просто и далеко не очевидно. Рассмотрим его более подробно.
На рис. 4.1 приведена блок-схема операций, выполняемых потоком при использовании мьютекса и условной переменной для синхронизации. Линиями отделены операции, выполняющиеся «внутри» функций, указанных справа. Обратите внимание, что наиболее сложная логика соответствует вызову функции ожидания на условной переменной.
Рис. 4.1. Схема действий потока при выполнении синхронизации с применением пары мьютекс-условная переменная (обратите внимание, что операции при участии мьютекса (1, 2, 3) выполняются дважды.)
Проблема в первую очередь заключается в том, что внутри критической секции, отмеченной вызовами функций
pthread_mutex_lock()
pthread_mutex_unlock()
pthread_cond_signal()
pthread_cond_broadcast()
Все функции операций над условной переменной и ее атрибутами реализованы в заголовочном файле
<pthread.h>
Операции над условной переменной
Параметры условной переменной
int pthread_condattr_init(pthread_condattr_t* attr);
Функция инициализирует структуру атрибутов условной переменной, на которую указывает параметр
attr
pthread_condattr_t
<pthread.h>
syncattr_t
Возвращаемые значения:
EOK
ENOMEM
attr
Для условной переменной возможна модификация значительно меньшего числа параметров, чем для мьютекса. Следующие функции описывают доступ к этим параметрам.
int pthread_condattr_setpshared(
pthread_condattr_t* attr, int pshared);
int pthread_condattr_getpshared(
const pthread_condattr_t* attr, int* pshared);
Функции устанавливают/считывают, возможен ли доступ к условной переменной из потоков, порожденных в других процессах. Параметр
pshared
•
PTHREAD_PROCESS_SHARED
•
PTHREAD_PROCESS_PRIVATE
PTHREAD_PROCESS_PRIVATE
Возвращаемые значения:
EOK
EINVAL
attr
pshared
int pthread_condattr_setclock(
pthread_condattr_t* attr, clockid_t id);
int pthread_condattr_getclock(
const pthread_condattr_t* attr, clockid_t* id);
Функции устанавливают/считывают, каким способом (т.e. на основании какого счетчика) вычисляется значение тайм-аута при вызовах
pthread_cond_timedwait()
REALTIME_CLOCK
id;
Возвращаемые значения:
EOK
EINVAL
attr.
Разрушение блока параметров
int pthread_condattr_destroy(pthread_condattr_t* attr);
Функция разрушает блок параметров условной переменной, на которые указывает
attr
На практике разрушение параметров объекта синхронизации не имеет особого смысла. Вы всегда можете переопределить атрибуты, содержащиеся в переменной
attr