Очень точная синхронизация

Очень точная синхронизация

Задержки

Прежде всего, я должен сказать, что в следствии многозадачной природы Linux, вы не можете гарантировать точную синхронизацию в пользовательской программе. Ваш процесс может выйти из расписания выполняемых задач на интервал от 10 миллисекунд до нескольких секунд (на системе с высокой загрузкой). Тем не менее, к большинству приложений, использующих порты ввода/вывода, это не относится. Чтобы свести это к минимуму, вы можете выполнять свой процесс при высоком приоритете (см. руководство nice(2)) или использовать расписание задач в реальном времени (см. ниже).

Если вам нужна более точная синхронизация в обычных пользовательских программах, существует несколько возможностей поддержки `реального времени' в пользовательском режиме. Ядра Linux версий 2.x имеют относительную поддержку реального времени; см. руководство по sched_setscheduler(2). Кроме того, существует специальное ядро, жестко поддерживающее реальное время; см. http://luz.cs.nmt.edu/~rtlinux/.

Задержка через порты ввода/вывода

Другой способ обеспечить задержку в несколько микросекунд - это порты ввода/вывода. Запись или чтение любого значения из порта 0x80 (о том, как это сделать, см. выше) обеспечивает задержку почти точно равную одной микросекунде, независимо от типа и скорости вашего процессора. Чтобы обеспечить задержку в несколько микросекунд, вы можете выполнить эту операцию несколько раз. Запись в этот порт не оказывает никакого влияния на компьютер (и некоторые драйверы используют это). Таким образом, обычно выполняется задержка в {in|out}[bw]_p() (см. asm/io.h).

На самом деле, операции ввода/вывода на большинство портов в диапазоне от 0 до 0x3ff тоже дают задержку около одной микросекунды. Так что, если вы, например, производите запись в параллельный порт, для обеспечения задержки, просто добавьте дополнительные inb() из порта.

Задержка при помощи команд ассемблера

Если вы знаете тип и частоту процессора машины, на которой будет работать программа, вы можете вставить меньшие задержки, путем выполнения определенных инструкций ассемблера (но помните, что ваш процесс может быть в любое время исключен из расписания, так что задержка может быть на много больше, чем вы хотите). В нижеуказанной таблице скорость процессора определяет число необходимых тактовых циклов для задержки; например, для процессора с частотой 50МГц (напр. 486DX-50 или 486DX2-50), один такт дает 1/50000000 секунд (=200 наносекунд).

Инструкция        такты i386         такты i486
nop                   3                   1
xchg %ax,%ax          3                   3
or %ax,%ax            2                   1
mov %ax,%ax           2                   1
add %ax,0             2                   1

(Прошу прощения, но я не знаю о Пентиуме; скорее всего, они близки к i486. На i386 я не смог найти инструкцию, выполняемую за один такт. В общем случае, лучше всего использовать одно-тактовые инструкции, иначе конвейерная обработка в современных процессорах может сократить задержку.)

Инструкции nop и xchg не должны давать посторонние эффекты. Остальные команды могут изменять регистр флагов процессора. Впрочем, это уже не имеет значение, т.к. gcc должен заметить это. Самый лучший выбор это nop.

Чтобы использовать это метод, выполните в вашей программе функцию asm("инструкция"). Синтаксис инструкций указан в таблице выше; если вы хотите указать несколько инструкций в одном asm(), разделите их точкой с запятой. Например, asm("nop ; nop ; nop ; nop") выполняет четыре инструкции nop, делая задержку в четыре такта на i486 или Pentium (или 12 тактов на i386).

Gcc непосредственно вставляет код из asm() в программу (inline), так что здесь нет никаких других задержек, связанных с вызовом функций.

Задержки менее одного такта невозможны на архитектуре Intel x86.



Наш баннер
Вы можете установить наш баннер на своем сайте или блоге, скопировав этот код:
RSS новости