[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

Программирование: Разработка и отладка программ


Планирование при синхронизации

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

Более подробно планирование синхронизации описывается в следующих разделах:

Инверсия приоритетов

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

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

Взаимная блокировка M защищает некоторый общий ресурс. Приоритет нити A равен 100. Она выполняется быстрее остальных нитей. Приоритет нити B равен 20. Эта нить выполняется в фоновом режиме. Приоритет остальных нитей процесса приблизительно равен 60. Ниже приведен фрагмент кода нити A:

pthread_mutex_lock(&M);             /* 1 */
...
pthread_mutex_unlock(&M);

Ниже приведен фрагмент кода нити B:

pthread_mutex_lock(&M);          /* 2 */
...
fprintf(...);                    /* 3 */
...
pthread_mutex_unlock(&M);

Рассмотрим следующий порядок выполнения нитей: запускается нить B и выполняется строка 2. После выполнения строки 3 нить B останавливается и запускается нить A. В ней выполняется только первая строка, после чего нить блокируется, так как взаимная блокировка M захвачена нитью B. В результате будут выполняться все остальные нити процесса. Поскольку приоритет нити B очень низкий, ее выполнение может возобновиться только через большой промежуток времени, в течение которого, несмотря на свой высокий приоритет, будет блокирована нить A.

Протоколы взаимных блокировок

Для предотвращения инверсии приоритетов в библиотеке нитей предусмотрено два протокола взаимных блокировок.

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

Протокол наследования приоритетов

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

Протокол защиты приоритетов

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

Выбор протокола взаимных блокировок

Протокол взаимных блокировок настраивается при создании взаимной блокировки путем задания атрибутов. Дополнительная информация по этому вопросу приведена в разделе Атрибут протокола. Рекомендации по выбору протокола приведены в разделе Выбор протокола наследования или защиты.

Атрибут протокола

Протокол взаимных блокировок настраивается с помощью специального атрибута протокола. Его можно задать в объекте атрибутов взаимной блокировки с помощью функций pthread_mutexattr_getprotocol и pthread_mutexattr_setprotocol. Допустимы следующие значения атрибута протокола:

PTHREAD_PRIO_NONE Протокол не выбран. Это значение по умолчанию.
PTHREAD_PRIO_INHERIT Протокол наследования приоритетов.
PTHREAD_PRIO_PROTECT Протокол защиты приоритетов.

В протоколе защиты приоритетов требуется настроить дополнительный атрибут. Он задает максимальный приоритет взаимной блокировки. Атрибут максимального приоритета хранится в объекте атрибутов взаимной блокировки и изменяется с помощью функций pthread_mutexattr_getprioceiling и pthread_mutexattr_setprioceiling.

Для динамического изменения максимального приоритета взаимной блокировки служат функции pthread_mutex_getprioceiling и pthread_mutex_setprioceiling. Обратите внимание, что при динамическом изменении приоритета взаимная блокировка захватывается библиотекой. Она не должна принадлежать нити, вызвавшей pthread_mutex_setprioceiling, для предотвращения тупика. Динамическое изменение максимального приоритета взаимной блокировки требуется при увеличении приоритета нити.

Реализации протоколов взаимных блокировок относятся к дополнительным функциям системы. Эти протоколы являются компонентами POSIX. Дополнительная информация о протоколах наследования и защиты приоритетов POSIX приведена в разделе Необязательные компоненты библиотеки работы с нитями.

Выбор протокола наследования или защиты

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

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

На выбор могут повлиять и повышенные требования к производительности программы. В большинстве реализаций, особенно в AIX, для изменения приоритета нити необходимо выполнить системный вызов. Протоколы взаимных блокировок различаются по числу генерируемых системных вызовов.

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

Связанная информация

Рекомендации по созданию программ с нитями

Планирование - Обзор

Планирование работы нитей

"Список функций планирования"

Необязательные компоненты библиотеки работы с нитями

 


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]