Битовые атомарные операции

Битовые атомарные операции

В дополнение к атомарным операциям с целыми числами, ядро также предоставляет семейство функций, которые позволяют работать на уровне отдельных битов. Не удивительно, что эти операции зависят от аппаратной платформы и определены в файле <asm/bitops.h>.

Тем не менее может вызвать удивление то, что функции, которые реализуют битовые операции, работают с обычными адресами памяти. Аргументами функций являются указатель и номер бита. Бит 0 — это наименее значащий бит числа, которое находится по указанному адресу. На 32-разрядных машинах бит 31 — это наиболее значащий бит, а бит 0 — наименее значащий бит машинного слова. Нет ограничений на значение номера бита, которое передается в функцию, хотя большинство пользователей работают с машинными словами и номерами битов от 0 до 31 (или до 63 для 64-битовых машин).

Так как функции работают с обычными указателями, то в этом случае нет аналога типу atomic_t, который используется для операций с целыми числами. Вместо этого можно использовать указатель на любые данные. Рассмотрим следующий пример.

unsigned long word = 0;

set_bit(0, &word);     /* атомарно устанавливается бит 0 */

set_bit(1, &word);     /* атомарно устанавливается бит 1 */

printk("%ul ", word); /* будет напечатано "3" */

clear_bit(1, &word);   /* атомарно очищается бит 1 */

change_bit(0, &word);  /* атомарно изменяется значение бита 1,

                          теперь он очищен */

/* атомарно устанавливается бит нуль и возвращается предыдущее

   значение этого бита (нуль) */

if (test_and_set_bit(0, &word)) {

 /* условие никогда не выполнится ... */

}

Список стандартных атомарных битовых операций приведен в табл. 9.2.

Таблица 9.2. Список стандартных атомарных битовых операций

Атомарная битовая операция Описание
void set_bit(int nr, void *addr) Атомарно установить nr-й бит в области памяти, которая начинается с адреса addr
void clear_bit(int nr, void *addr) Атомарно очистить nr-й бит в области памяти, которая начинается с адреса addr
void change_bit(int nr, void *addr) Атомарно изменить значение nr-го бита в области памяти, которая начинается с адреса addr, на инвертированное
int test_and_set_bit(int nr, void *addr) Атомарно установить значение nr-го бита в области памяти, которая начинается с адреса addr, и возвратить предыдущее значение этого бита
int test_and_clear_bit(int nr, void *addr) Атомарно очистить значение nr-го бита в области памяти, которая начинается с адреса addr, и возвратить предыдущее значение этого бита
int test_and_change_bit(int nr, void *addr) Атомарно изменить значение nr-го бита в области памяти, которая начинается с адреса addr, на инвертированное и возвратить предыдущее значение этого бита
int test_bit(int nr, void *addr) Атомарно возвратить значение nr-го бита в области памяти, которая начинается с адреса addr

Для удобства работы также предоставляются неатомарные версии всех битовых операций. Эти операции работают так же, как и их атомарные аналоги, но они не гарантируют атомарности выполнения операций, и имена этих функций начинаются с двух символов подчеркивания. Например, неатомарная форма функции test_bit() будет иметь имя __test_bit(). Если нет необходимости в том, чтобы операции были атомарными, например, когда данные уже защищены с помощью блокировки, неатомарные операции могут выполняться быстрее.

Откуда берутся неатомарные битовые операции

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

Давайте вспомним, что такое атомарность? Атомарность означает, что операция или завершается полностью, не прерываясь, или не выполняется вообще. Следовательно, если выполняется две атомарные битовые операции, то предполагается, что они обе должны выполниться. Понятно, что значение бита должно быть правильным (и равным тому значению, которое устанавливается с помощью последней операции, как рассказано в конце предыдущего параграфа). Более того, если другие битовые операции тоже выполняются успешно, то в некоторые моменты времени значение бита должно соответствовать тому, которое устанавливается этими промежуточными операциями.

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

Иногда может требоваться именно такое поведение, особенно если критичен порядок выполнения.

Ядро также предоставляет функции, которые позволяют найти номер первого установленного (или не установленного) бита, в области памяти, которая начинается с адреса addr:

int find_first_bit(unsigned long *addr, unsigned int size);

int find_first_zero_bit(unsigned long *addr, unsigned int size);

Обе функции в качестве первого аргумента принимают указатель на область памяти и в качестве второго аргумента — количество битов, по которым будет производиться поиск. Эти функции возвращают номер первого установленного или не установленного бита соответственно. Если код производит поиск в одном машинном слове, то оптимальным решением будет использовать функции __ffs() и __ffz(), которые в качестве единственного параметра принимают машинное слово, где будет производиться поиск.

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

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Операции

Из книги Модель зрелости процессов разработки программного обеспечения автора Паулк Марк

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


R.9.6 Битовые поля

Из книги Справочное руководство по C++ автора Страустрап Бьярн

R.9.6 Битовые поля Конструкция описатель-члена, имеющая вид,идентификатор opt : выражение-константазадает битовое поле, длина которого отделяется от его имени двоеточием. Размещение битовых полей в объекте класса зависит от реализации. Поля упаковываются в некоторые


Операции += и -=

Из книги Язык программирования С# 2005 и платформа .NET 2.0. [3-е издание] автора Троелсен Эндрю

Операции += и -= Если вы изучаете C#, уже имея опыт использования C++, то можете обратить внимание на отсутствие возможности перегрузки операторных сокращений, включающих операцию присваивания (+=, -= и т.д.). Не волнуйтесь, в C# операторные сокращения с присваиванием


Код операции MI

Из книги Основы AS/400 автора Солтис Фрэнк

Код операции MI В таблице 4.14 показано назначение битов кода операции MI. Бит 3 задает вычислительный или невычислительный формат команды. Во втором случае функция, которая должна быть выполнена, закодирована в битах 5-15 кода операции. Функция, выполняемая вычислительной


D.1.4 10-битовые подсети

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

D.1.4 10-битовые подсети Начнем с более простого случая для сети 130.15.1. Первый хост будет иметь адрес:10000010 00001111 00000001 00000001130 . 15 . 1 .1Последний хост этой подсети получит адрес:10000010 00001111 00000001 00111110130 . 15 . 1 . 62Записанная с точками, подсеть будет содержать 62 адреса:от 130.15.1.1 до


16.1. Операции tty

Из книги Разработка приложений в среде Linux. Второе издание автора Джонсон Майкл К.

16.1. Операции tty Устройства tty предоставляют огромное количество опций обработки данных; они относятся к наиболее сложным устройствам ядра. Настраивать можно опции обработки входных и выходных данных, а также потока данных. Также можно контролировать ограниченное


Операции

Из книги Язык программирования Си для персонального компьютера автора Бочков C. О.


Операции

Из книги QNX/UNIX [Анатомия параллелизма] автора Цилюрик Олег Иванович

Операции Операции в языке Си имеют либо один операнд (унарные операции), либо два операнда (бинарные операции), либо три (тернарная операция). Операция присваивания может быть как унарной, так и бинарной (см. раздел 4.4).Существенным свойством любой операции является ее


Операции

Из книги C++ для начинающих автора Липпман Стенли

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


Операции

Из книги Разработка ядра Linux автора Лав Роберт

Операции Теперь рассмотрим, что можно и нельзя делать с величинами типа enum. Вы можете присвоить константу типа enum переменной того же типа enum feline pet;pet = tiger;Нельзя использовать другие операции присваивания: pet += cat; /* недопустимо */Можно провести сравнение с целью выявления


4.3. Операции сравнения и логические операции

Из книги Описание языка PascalABC.NET автора Коллектив РуБоард

4.3. Операции сравнения и логические операции Символ операции Значение Использование ! Логическое НЕ !expr меньше exprexpr = Меньше либо равно expr=expr больше exprexpr = больше либо равно expr=expr == равно expr==expr != не равно expr!=expr логическое


Атомарные операции

Из книги автора

Атомарные операции Атомарные операции (atomic operations) предоставляют инструкции, которые выполняются атомарно, — т.е. не прерываясь. Так же как и атом вначале считался неделимой частицей, атомарные операции являются неделимыми инструкциями. Например, как было показано в


Целочисленные атомарные операции

Из книги автора

Целочисленные атомарные операции Средства выполнения атомарных операций с целыми числами работают с типом данных atomic_t. Вместо того, чтобы использовать функции, которые работают непосредственно с типом данных int языка С, по ряду причин используется специальный тип


Операции is и as

Из книги автора

Операции is и as Операция is предназначена для проверки того, имеет ли классовая переменная указанный динамический тип. Операция as позволяет безопасно преобразовать переменную одного классового типа к другому классовому типу (в отличие от явного приведения классового