Занято ожиданием - Busy waiting

В Информатика и программная инженерия, занято-ожидание, зацикленный или прядение это техника, в которой обработать неоднократно проверяет, выполняется ли условие, например, клавиатура ввод или замок доступен. Вращение также можно использовать для генерации произвольной задержки по времени, метод, который был необходим в системах, в которых отсутствовал метод ожидания определенного периода времени. Скорость процессора сильно различается от компьютера к компьютеру, особенно потому, что некоторые процессоры предназначены для динамической регулировки скорости в зависимости от текущей рабочей нагрузки.[1]. Следовательно, вращение как метод задержки по времени может давать непредсказуемые или даже противоречивые результаты в разных системах, если не включен код, определяющий время, необходимое процессору для выполнения команды «ничего не делать». петля, или код цикла явно проверяет часы реального времени.

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

Пример кода C

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

#включают <pthread.h>#включают <stdatomic.h>#включают <stdio.h>#включают <stdlib.h>#включают <unistd.h>/ * i глобальный, поэтому он виден всем функциям. Он использует специальные * тип atomic_int, разрешающий атомарный доступ к памяти. */atomic_int я = 0;/ * f1 использует спин-блокировку, чтобы ждать, пока i изменится с 0. * /статический пустота *f1(пустота *п){    int local_i;    / * Атомно загружаем текущее значение i в local_i и проверяем, если это значение       равно нулю * /    в то время как ((local_i = atomic_load(&я)) == 0) {        / * ничего не делать - просто проверять снова и снова * /    }    printf("значение i изменилось на% d. п", local_i);    вернуть ЗНАЧЕНИЕ NULL;}статический пустота *f2(пустота *п){    int local_i = 99;    спать(10);   / * засыпаем 10 секунд * /    atomic_store(&я, local_i);    printf("t2 изменил значение i на% d. п", local_i);    вернуть ЗНАЧЕНИЕ NULL;}int основной(){    int rc;    pthread_t t1, t2;    rc = pthread_create(&t1, ЗНАЧЕНИЕ NULL, f1, ЗНАЧЕНИЕ NULL);    если (rc != 0) {        fprintf(stderr, "pthread f1 не удалось п");        вернуть EXIT_FAILURE;    }    rc = pthread_create(&t2, ЗНАЧЕНИЕ NULL, f2, ЗНАЧЕНИЕ NULL);    если (rc != 0) {        fprintf(stderr, "pthread f2 не удалось п");        вернуть EXIT_FAILURE;    }    pthread_join(t1, ЗНАЧЕНИЕ NULL);    pthread_join(t2, ЗНАЧЕНИЕ NULL);    ставит("Все нитки закончены".);    вернуть 0;}

В таком случае использования можно рассмотреть возможность использования C11 с переменные состояния.

Альтернативы

Большинство операционных систем и потоковых библиотек предоставляют различные системные вызовы что будет блокировать процесс события, например получение блокировки, изменение таймера, Ввод / вывод наличие или сигналы. Использование таких вызовов обычно дает наиболее простые, эффективные, справедливые и гонка -бесплатный результат. Одиночный вызов проверяет, информирует планировщик о событии, которого он ожидает, вставляет барьер памяти где это применимо, и может выполнить запрошенную операцию ввода-вывода перед возвратом. Другие процессы могут использовать ЦП, пока вызывающий абонент заблокирован. Планировщику предоставляется информация, необходимая для реализации наследование приоритета или другие механизмы, чтобы избежать голодание.

Ожидание занятости можно сделать гораздо менее расточительным, если использовать функцию задержки (например, спать()) встречается в большинстве операционных систем. Это переводит поток в спящий режим на определенное время, в течение которого поток не будет тратить время ЦП. Если цикл проверяет что-то простое, он будет проводить большую часть времени в спящем режиме и тратить очень мало времени процессора.

В программах, которые никогда не заканчиваются (например, в операционных системах), бесконечное ожидание занятости может быть реализовано с помощью безусловных переходов, как показано этим NASM синтаксис: jmp $. ЦП безоговорочно Прыгать к его собственная позиция навсегда. Такое напряженное ожидание можно заменить на:

спать:hltjmp спать

Для получения дополнительной информации см. HLT (инструкция x86).

Соответствующее использование

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

Смотрите также

использованная литература

  1. ^ «Технология Intel Turbo Boost».
  2. ^ «Почему не следует использовать класс типа volatile». В архиве из оригинала на 2017-10-04. Получено 2013-06-10.

внешние ссылки