Проверка list_empty без блокировки - PullRequest
1 голос
/ 17 марта 2020

Меня интересует безопасность потоков в связанном списке ядра linux. Предположим, что один поток добавляет элементы в список, а другой поток читает список. Конечно, при изменении списка мне нужно взять блокировку / мьютекс. Но требует ли проверка того, что список пуст с помощью list_empty, уже требует блокировки?

Глядя на источник list_empty:

static inline int list_empty(const struct list_head *head)
{
    return READ_ONCE(head->next) == head;
}

, мы видим, что он использует READ_ONCE. AFAIK это предотвращает некоторые оптимизации компилятора, а также атомы c для правильно выровненных / размерных переменных. Поскольку нет никакого барьера памяти, я не получаю никакого заказа с другими обращениями к памяти вообще, но список в конечном счете станет не пустым после того, как некоторый другой поток добавил элемент. Поэтому я считаю, что блокировка не является строго необходимой для list_empty.

Я спрашиваю, потому что хочу использовать list_empty в качестве условия для wait_event_interruptible.

1 Ответ

0 голосов
/ 17 марта 2020

Давайте использовать псевдо-ассемблер.

Чтобы прочитать head->next, нужно прочитать head.

mov ax, head                 (1)

Затем он принимает смещение следующего и получает next:

mov cx, [ax+offset(next)]    (2)

Теперь он сравнивает его с head:

cmp ax,cx                    (3)

Если предположить, что head не изменяется и не равен нулю (например, глобальная переменная), тогда шаг (2) имеет атоми c, и блокировка не требуется. Однако, если head может измениться , то шаг 2 может извлечь неправильные данные, поскольку ax может больше не быть действительным, например, потому что планировщик приостановил задачу после шага 1, и три шага должны быть выполняется в заблокированном состоянии.

...