1

Я пытаюсь понять, как работает код ниже. Это прямо из моих лекционных лекций. Эта функция P() и V() является частью реализации семафора в ОС, которую мы используем в классе (OS161). Я думаю, вам может понадобиться понимание OS161, чтобы ответить на мой вопрос, поскольку он широко используется, надеюсь, кто-то может ответить на эти вопросы.

Мое понимание этого кода с конспектов:
X: Поток функции
1. Когда поток вызова P(), мы отключаем прерывания
2. Проверьте, если мы имеем P() любые ресурсы, доступные на sem-> count
3.a) если count 0, то мы идем спать
3.b) если count! = 0, то мы уменьшаем счетчик и разрешаем вызывающему потоку продолжать критический раздел
4. Включить прерывание
Y: Течение функции V()
1. Когда поток вызовов В(), мы отключить прерывания
2. Увеличить счетчик, подразумевая, что теперь есть 1 еще ресурс доступен, чтобы захватить
3. Теперь мы идем вперед и просыпаемся все нити, которые мы отправили спать в P(), потому что не были доступны достаточно ресурсов, в то время поток пытался захватить замок в критическую секцию
4. Включение прерываний
Как спящие потоки отключены?

Мои проблемы:
1. Отключает ли раздел «отключить прерывание» прерывание на определенном уровне объявление или отключает все прерывания?
2. В функции V(), когда мы пробуждаем все потоки, поток, посланный внутри цикла while в функции P(), запускает цикл while. В лекции говорится, что одна нить захватывает замок и отдыхает спать. Мой вопрос в том, почему «sem-> count == 0» условие не оценивает false для других потоков, а только для одного.

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

Почему нить идет спать с отключением прерывания? это не так опасно, так как он может пропустить готовые сигналы ввода-вывода и другие вещи?

P(sem) { 
     Disable interrupts; 
     while (sem->count == 0) { 
     thread_sleep(sem); /* current thread 
           will sleep on this sem */ 
     } 
     sem->count--; 
     Enable interrupts; 
    } 
    V(sem) { 
     Disable interrupts; 
     sem->count++; 
     thread_wakeup (sem); /* this will wake 
     up all the threads waiting on this 
        sem. Why wake up all threads? */ 
     Enable interrupts; 
    } 

спасибо.

ответ

5

ЦП ничего не знает о потоках, это всего лишь логическая/абстрактная концепция, реализованная в программном обеспечении. Но ЦП знает о прерываниях, они реальны, и всякий раз, когда кто-то приходит с какого-либо устройства, ЦП прекращает выполнение того, что он выполнял, и начинает выполнение подпрограммы, посвященной обработке этого конкретного прерывания. Как только это будет сделано, рутинные сигналы завершат обработку прерываний, а процессор возобновляет выполнение того, что было вытеснено процедурой обработки прерываний.

Если выгруженный код принадлежит потоку, пусть будет так. Если это была другая процедура обработки прерываний, тоже.

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

Итак, вы можете использовать прерывания для переключения между различными частями кода, потоками или тем, что у вас есть. Фактически, это точно, сколько планировщиков работает. Они получают периодические прерывания от таймера и в обработчике прерываний сохраняют контекст выгруженного кода (например, поток A) в памяти и загружают контекст другого выгруженного кода (например, поток B) из памяти и возвращают, тем самым продолжая выполнение в другом потоке ,

Если вы отключите эти таймерные прерывания, также будет отключено периодическое планирование/переключение потоков. Прерывания влияют на весь процессор и текущий исполняемый поток (или что бы то ни было), а по индукции влияют на все потоки.

Есть?

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

Итак, когда поток блокируется семафором или каким-либо другим примитивом синхронизации, планировщик просто выбирает другой поток для выполнения. Если все потоки заблокированы, выбран фиктивный поток.

В вашем коде прерывания отключены на короткий период времени, а код ядра управляет различными глобальными переменными (например, списками заблокированных/спящих и готовых потоков). Это нормально. Здесь вы не хотите участвовать в гонке. Прерывания снова включаются, когда планировщик выбирает другой поток для выполнения и продолжает его выполнять.

Заметим, что, когда в-какой-точечным текущий поток заканчивает спать (например, когда другой поток будит его), он всегда разрешает прерывания:

spl = splhigh(); // disable interrupts 
while (sem->count==0) { 
    thread_sleep(sem); // context switch (to another thread and then back) occurs here 
} 
sem->count--; 
splx(spl); // <-- re-enable interrupts here 

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

Просто подумайте об этом. У вас есть 2 (или более) экземпляра вышеупомянутого или аналогичного кода в 2 (или более) потоках. Когда один входит в thread_sleep() или аналогичную функцию, другой поток выходит из своего thread_sleep() или аналогичной функции и повторно включает прерывания.

Следуйте код и комментарии по этому пути:

P()
    thread_sleep()
        mi_switch()
            md_switch()
                mips_switch()

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

Смежные вопросы