Плюсы и минусы с готовой очередью для разных семафоров в мини ОС - PullRequest
2 голосов
/ 25 мая 2010

В ОС у нас изначально есть готовая очередь для потоков, обратите внимание только на одну очередь. Почему было бы лучше иметь разные очереди для каждого семафора. Плюсы и минусы могут быть связаны с эффективностью, сложностью или чем-то еще.

Ответы [ 2 ]

3 голосов
/ 26 мая 2010

Хорошо, чтобы ответить на этот вопрос, пожалуйста, обратитесь к моему ответу на другой вопрос здесь, в SO, относительно «Процессы или потоки с разделением времени в Linux?», Давайте продолжим из этой воображаемой структуры Ядро здесь с использованием процессора x86 и кода C ... Я изменил эту структуру, чтобы учесть семафоры

struct regs{
  int eax, ebx, ecx, edx, es, ds, gs, fs, cs, ip, flags;
  struct tss *task_sel;
}

struct mem_loc{
   int *phys_mem_begin;
   int *phys_mem_end;
   int *semaphores;
}
struct thread{
    struct regs *regs;
    struct mem_loc *memlocTracker;
    int parent_id;
    struct thread *next;
}
struct task{
   struct regs *regs;
   struct mem_loc *task_mem;
   int *filehandles;
   int priority;
   int *num_threads;
   int quantum;
   int duration;
   int start_time, end_time;
   int parent_id;
   struct thread *task_thread;
     /* ... */
   struct task *next;
}

struct queue_ready{
   struct task *task_id;
   struct queue_ready *next;
}

Там, я думаю, это выглядит лучше, верно, в отношении продолжения моего предыдущего ответа, связанного выше, давайте посмотрим, что происходит, когда есть очереди, теперь, давайте посмотрим на эту queue_ready структуру, теперь, предположим, что есть задача в этой структуре, установленной ядром, точнее, связанный список queue_ready, основанный на поле priority самой структуры task, и приоритет равен, например, 1 готов к исполнению.

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

static void scheduler(void){
 struct queue_ready *rdy_sched;

 while(1){

   for (rdy_sched = head_queue_ready; 
        rdy_sched != NULL; 
        rdy_sched = rdy_sched->next){

     if (time >= rdy_sched->task_id->start_time + rdy_sched->task_id->quantum){

        save_cpu_task_state(&task_reg->regs);

        save_mem_task_state(&rdy_sched->task_id->task_mem);

     }else{
       struct regs *task_reg = rdy_sched->task_id->regs;

       struct mem_loc *mem_task = rdy_sched->task_id->task_mem;

       load_cpu_task_state(task_reg);

       load_mem_task_state(mem_task);

       jmp_and_exec_cpu_task(task_reg->cs, task_reg->ip);

       save_cpu_task_state(&rdy_sched->task_id->regs);

       if (rdy_sched->task_id->num_threads > 0){

         struct thread *threads = rdy_sched->task_id->task_thread;

         while (threads->next != NULL){

           struct regs *thread_reg = threads->regs;

           load_cpu_thread_state(thread_reg);

           if (threads->memlocTracker->semaphores){

             /* House keeping in relation to semaphores */
             lock_memory(threads->memlocTracker);

             jmp_and_exec_cpu_thread(thread_reg->cs, thread_reg->ip);

             save_cpu_thread_state(&thread->regs);

             unlock_memory(threads->memlocTracker);

           }else{

             jmp_and_exec_cpu_thread(thread_reg->cs, thread_reg->ip);

             save_cpu_thread_state(&thread->regs);
           }
         }
       }
     }
   }
 }
}

Планировщик ядра выглядит слишком сложным, но на самом деле это не так, единственное упущение, которое я пропустил в коде, - это приоритеты, которые теперь можно игнорировать при обсуждении вопроса ОП.

Давайте разберем эту функцию планировщика scheduler вниз ... но сначала быстрый взгляд и объяснение того, какие функции используются в функции scheduler:

  • 'load_cpu_task_state' и 'load_cpu_thread_state' - это загружает состояние регистров ЦП, для краткости они для задачи и потока соответственно.
  • 'load_mem_task_state' и 'save_mem_task_state' - загружает и сохраняет соответственно состояние памяти, возможно, на / со страницы на диске, заданной полями phys_mem_begin и phys_mem_end структуры mem_loc для указанного задача. Для краткости это загрузит всю память, принадлежащую указанной задаче, включая потоки.
  • 'jmp_and_exec_cpu_task' и 'jmp_and_exec_cpu_task' - это заставляет ядро ​​выдавать магию при переходе к указанным cs и ip регистрам структуры reg указанной задачи, также то же самое для потока соответственно.
  • 'save_cpu_task_state' и 'save_cpu_thread_state' - это заставляет ядро ​​сохранять состояние регистров ЦП как для задачи, так и для потока соответственно.
  • 'lock_memory' и 'unlock_memory' - это для блокировки области памяти с помощью семафоров, которые вскоре вступят в игру ...

Теперь scheduler выполняется вечно и выполняет итерацию по связанному списку задач; требуется проверка, чтобы убедиться, что задача выполнялась в течение определенного периода и превысила сумму quantum, например, 20 мс. Затем он сохраняет состояние процессора и состояние памяти (возможно, сохраняется в файле подкачки на диске), готовый перейти к следующей задаче в списке.

Если остается еще время, он загружает регистры ЦП задачи и загружает память (возможно, со страницы) и переходит туда, где был последний указатель инструкции и сегмент кода (ip и cs соответственно), и задача возобновляется. ,

Если в указанной задаче есть потоки, она будет перебирать связанный список потоков, загружать регистры ЦП и переходить в код, чтобы возобновить выполнение потоков, а затем сохранять регистры ЦП.

Теперь, когда все становится немного странно, особенно в этой игрушечной ОС, как управлять семафорами! э-э, похоже, большая головная боль нависла над головой разработчика ОС ....

Я бы предположил, что если часть памяти заблокирована, semaphores будет отличным от NULL и будет получен менеджером среды выполнения в коде пользовательской земли, который запрашивает семафор, он заблокирует память, чтобы предотвратить потоптывая данные, переходя к коду для указанного потока, разблокирует его, когда продолжительность этого потока завершится, и сохранит это состояние регистров ЦП потока ...

Вывод:

Это мой вывод, основанный на этом, что касается фактов, подтверждающих меня, я не могу, так как эта теория была подробно прочитана, изучена под микроскопом в бесчисленных книгах, начиная от Университета в США, вплоть до самого конца. Что касается университета в Новой Зеландии, то это из моих наблюдений и моего понимания, как вы можете видеть из этого кода, сложности и бремени, налагаемого на разработчика при кодировании этого, а не только этого, наложенных ограничений, проектных решений - оба железо и софт.

Управлять семафорами в этом контексте гораздо сложнее, если ответить, если было доступно больше очередей, как я стремился сохранить в одной очереди queue_ready, фактор стоимости с точки зрения использования памяти, использования диска и выше все время использования растет по мере того, как ядро ​​должно будет отслеживать те смягчающие факторы, которые вступают в игру, еще один не менее важный фактор - это то, сколько приоритетов будет, поэтому, по моему мнению, наличие очереди для разных семафоров не является Жизнеспособный и выполнимый вариант.

1 голос
/ 25 мая 2010

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

Что находится в вашей очереди? Большинство готовых очередей, которые я видел, содержат список всех потоков, которые готовы к запуску. Это, конечно, отличается от всех потоков в системе. Если эта модель соответствует вашим настройкам, я бы рекомендовал придерживаться одной готовой очереди. Когда дело доходит до планирования или выбора следующего потока для запуска, вам нужно проверить только одну очередь, и вам не нужно беспокоиться о приостановленных задачах в этой очереди.

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

Выполнение этого помогает сохранить потоки в похожих состояниях вместе. Следовательно, когда вам приходится искать в этих списках, вы можете свести к минимуму накладные расходы.

Надеюсь, это поможет.

...