xv6: читать тики напрямую, не блокируя тики? - PullRequest
2 голосов
/ 25 марта 2019

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

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

Поскольку переменная тиков используется только так: ticks++, есть ли способ, где я попытаюсь получить текущее количество тиков и получить неправильное число?

Я не против получить неправильное число с помощью + -10 тиков, но есть ли способ, по которому оно действительно будет отключено. Например, когда число 01111111111111111 будет увеличиваться, потребуется изменить 2 байта. Итак, мой вопрос заключается в следующем: возможно ли, чтобы ЦП сохранял данные поэтапно, а другой ЦП мог бы получать данные в этом месте памяти между началом и завершением операции сохранения?

Итак, на мой взгляд, если компилятор создаст инструкцию mov или инструкцию inc, я хочу знать, можно ли увидеть операцию сохранения между ее началом и концом.

Ответы [ 2 ]

1 голос
/ 04 июня 2019

В asm нет проблем: выровненные загрузки / хранилища, выполненные с помощью одной инструкции на x86, имеют атомарную ширину до qword (8 байт). Почему целочисленное присваивание для естественно выровненной переменной атомарно в x86?

(На 486 гарантия распространяется только на 4-байтовые выровненные значения, а может даже и на 386, поэтому, возможно, именно поэтому Xv6 использует блокировку? Я не уверен, что она должна быть многоядерной безопасной на 386. Насколько я понимаю, на редких компьютерах 386 SMP не совсем реализована современная модель памяти x86 (упорядочение памяти и т. Д.).

Но C не является asm. Использование простой не-atomic переменной из нескольких «потоков» одновременно является неопределенным поведением, если только все потоки не только читают. Это означает, что компиляторы могут предполагать, что обычная переменная C не изменяется асинхронно другими потоками.

Использование ticks в цикле в C позволит компилятору прочитать его один раз и постоянно использовать одно и то же значение . Вам нужен макрос READ_ONCE, который используется в ядре Linux, например, *(volatile int*)&ticks. Или просто объявите это как volatile unsigned ticks;


Для переменной, достаточно узкой, чтобы поместиться в один целочисленный регистр, вероятно, можно с уверенностью предположить, что здравомыслящий компилятор запишет ее с одним хранилищем слов, будь то mov или место назначения памяти inc или add dword [mem], 1. (Вы не можете предполагать, что компилятор будет использовать место назначения памяти inc / add, поэтому вы не можете зависеть от приращения одноядерного атома по отношению к прерываниям.)

С одним писателем и несколькими читателями, да, читатели могут просто читать его без какой-либо блокировки, если они используют volatile.

Даже в portable ISO C, volatile sig_atomic_t имеет некоторые очень ограниченные гарантии безопасной работы при записи обработчиком сигнала и чтении потоком, который выполнял обработчик сигнала. (Не обязательно для других потоков, хотя: в ISO C volatile не избегает гонки данных UB. Но на практике на x86 с не враждебными компиляторами это нормально.)

(Сигналы POSIX являются эквивалентом прерываний в пользовательском пространстве).

См. Также Может ли num ++ быть атомарным для 'int num'?

Чтобы один поток опубликовал более широкий счетчик в две половины, вы обычно используете SeqLock. С 1 записывающим устройством и несколькими считывающими устройствами нет никакой реальной блокировки, просто повторите действия читателей, если запись перекрывается с их чтением. См. Реализация 64-битного атомного счетчика с 32-битным атомом

0 голосов
/ 26 марта 2019

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

Во-вторых, в описываемом вами конкретном случае будет безопасно читать переменную тиков без каких-либо блокировок, поскольку это не случай гонки, поскольку доступ к ОЗУ в том же регионе (даже в том же адресе здесь) не могут быть выполнены двумя отдельными процессорами одновременно ( читать дальше ), и потому что запись тиков только увеличивает значение на 1 и не вносит каких-либо серьезных изменений, которые вам действительно не хватает.

...