Программа на C++ для алгоритма планирования FCFS

C++C++Beginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом практическом занятии мы реализуем алгоритм планирования "Первым пришел - первым обслужен" (First Come First Serve, FCFS) с использованием языка программирования C++. FCFS является самым простым алгоритмом планирования процессора, который выделяет процессор процессам в порядке их запроса. Процесс, который первым попадает в очередь готовых, обслуживается первым.

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


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("C++")) -.-> cpp/BasicsGroup(["Basics"]) cpp(("C++")) -.-> cpp/IOandFileHandlingGroup(["I/O and File Handling"]) cpp/BasicsGroup -.-> cpp/variables("Variables") cpp/BasicsGroup -.-> cpp/arrays("Arrays") cpp/IOandFileHandlingGroup -.-> cpp/output("Output") cpp/IOandFileHandlingGroup -.-> cpp/user_input("User Input") cpp/IOandFileHandlingGroup -.-> cpp/files("Files") subgraph Lab Skills cpp/variables -.-> lab-96161{{"Программа на C++ для алгоритма планирования FCFS"}} cpp/arrays -.-> lab-96161{{"Программа на C++ для алгоритма планирования FCFS"}} cpp/output -.-> lab-96161{{"Программа на C++ для алгоритма планирования FCFS"}} cpp/user_input -.-> lab-96161{{"Программа на C++ для алгоритма планирования FCFS"}} cpp/files -.-> lab-96161{{"Программа на C++ для алгоритма планирования FCFS"}} end

Понимание алгоритма FCFS и создание структуры программы

Алгоритм "Первым пришел - первым обслужен" (First Come First Serve, FCFS) является непредвытесняющим алгоритмом планирования, в котором процессы выполняются в порядке их поступления в очередь готовых. На этом этапе мы создадим файл программы и настроим ее базовую структуру.

Начнем с создания нового файла на языке C++:

  1. Откройте интерфейс WebIDE и перейдите в панель проводника файлов.
  2. Щелкните правой кнопкой мыши в панели проводника и выберите "Новый файл".
  3. Назовите файл fcfs.cpp и нажмите Enter.

Теперь добавим в нашу программу необходимые заголовочные файлы и объявление пространства имен:

#include <iostream>
#include <iomanip> // For formatted output

using namespace std;

int main() {
    cout << "FCFS Scheduling Algorithm Implementation" << endl;
    cout << "----------------------------------------" << endl;

    return 0;
}

Этот код устанавливает базовую структуру нашей программы с:

  • #include <iostream> - Для операций ввода/вывода.
  • #include <iomanip> - Для форматирования таблицы вывода.
  • using namespace std; - Чтобы использовать стандартное пространство имен.
  • Функцией main(), которая отображает заголовок.

Скомпилируем и запустим программу, чтобы убедиться, что все настроено правильно:

g++ fcfs.cpp -o fcfs
./fcfs

Вы должны увидеть следующий вывод:

FCFS Scheduling Algorithm Implementation
----------------------------------------

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

Реализация функциональности ввода данных о процессах

На этом этапе мы реализуем функциональность для сбора информации о процессах, которые будут запланированы. Для алгоритма планирования FCFS нам нужно знать:

  1. Количество процессов.
  2. Время выполнения (burst time) каждого процесса (время, необходимое для выполнения каждого процесса).

Давайте модифицируем наш файл fcfs.cpp, чтобы включить эту функциональность:

#include <iostream>
#include <iomanip> // For formatted output

using namespace std;

int main() {
    cout << "FCFS Scheduling Algorithm Implementation" << endl;
    cout << "----------------------------------------" << endl;

    // Variables declaration
    int n;                  // Number of processes
    int burst_time[20];     // Array to store burst time of each process

    // Get the number of processes from the user
    cout << "\nEnter the number of processes (maximum 20): ";
    cin >> n;

    // Input validation
    if (n <= 0 || n > 20) {
        cout << "Invalid number of processes. Please enter a value between 1 and 20." << endl;
        return 1;
    }

    // Get burst time for each process
    cout << "\nEnter the Burst Time for each process:" << endl;
    for (int i = 0; i < n; i++) {
        cout << "Process P" << i + 1 << ": ";
        cin >> burst_time[i];

        // Input validation for burst time
        if (burst_time[i] <= 0) {
            cout << "Burst time must be a positive integer. Please restart the program." << endl;
            return 1;
        }
    }

    // Display the entered data
    cout << "\nProcess\tBurst Time" << endl;
    cout << "--------------------" << endl;
    for (int i = 0; i < n; i++) {
        cout << "P" << i + 1 << "\t" << burst_time[i] << endl;
    }

    return 0;
}

Разберем, что мы добавили:

  1. Переменные для хранения количества процессов (n) и времени выполнения каждого процесса (burst_time[20]).
  2. Подсказки для ввода данных, чтобы собрать количество процессов и время выполнения каждого процесса.
  3. Валидация ввода, чтобы убедиться, что количество процессов находится в разумном диапазоне (от 1 до 20) и времена выполнения положительные.
  4. Отображение таблицы с введенными данными для проверки.

Скомпилируем и запустим нашу обновленную программу:

g++ fcfs.cpp -o fcfs
./fcfs

При запуске программы вас попросят ввести количество процессов и их времена выполнения. Попробуйте ввести следующие данные:

3
5
9
4

Это представляет 3 процесса с временами выполнения 5, 9 и 4 единиц времени соответственно. Вы должны увидеть вывод, похожий на следующий:

FCFS Scheduling Algorithm Implementation
----------------------------------------

Enter the number of processes (maximum 20): 3

Enter the Burst Time for each process:
Process P1: 5
Process P2: 9
Process P3: 4

Process Burst Time
--------------------
P1      5
P2      9
P3      4

Это подтверждает, что наша функциональность ввода работает правильно. На следующем этапе мы вычислим время ожидания и время выполнения для каждого процесса.

Вычисление времени ожидания и времени выполнения

На этом этапе мы вычислим два важных показателя для каждого процесса:

  1. Время ожидания (Waiting Time, WT): Время, в течение которого процесс ожидает в очереди готовых до получения времени ЦП.
  2. Время выполнения (Turnaround Time, TAT): Общее время, затраченное на выполнение процесса от момента его подачи до завершения.

Понятно, как эти показатели вычисляются в алгоритме FCFS:

  • Для первого процесса (P1) время ожидания всегда равно 0 (он начинается сразу).
  • Для последующих процессов время ожидания равно сумме времен выполнения (burst time) всех предыдущих процессов.
  • Время выполнения для каждого процесса равно сумме его времени выполнения и времени ожидания.

Теперь модифицируем наш файл fcfs.cpp, чтобы добавить эти вычисления:

#include <iostream>
#include <iomanip> // For formatted output

using namespace std;

int main() {
    cout << "FCFS Scheduling Algorithm Implementation" << endl;
    cout << "----------------------------------------" << endl;

    // Variables declaration
    int n;                      // Number of processes
    int burst_time[20];         // Array to store burst time of each process
    int waiting_time[20];       // Array to store waiting time of each process
    int turnaround_time[20];    // Array to store turnaround time of each process
    int total_waiting_time = 0;
    int total_turnaround_time = 0;

    // Get the number of processes from the user
    cout << "\nEnter the number of processes (maximum 20): ";
    cin >> n;

    // Input validation
    if (n <= 0 || n > 20) {
        cout << "Invalid number of processes. Please enter a value between 1 and 20." << endl;
        return 1;
    }

    // Get burst time for each process
    cout << "\nEnter the Burst Time for each process:" << endl;
    for (int i = 0; i < n; i++) {
        cout << "Process P" << i + 1 << ": ";
        cin >> burst_time[i];

        // Input validation for burst time
        if (burst_time[i] <= 0) {
            cout << "Burst time must be a positive integer. Please restart the program." << endl;
            return 1;
        }
    }

    // Calculate waiting time for each process
    waiting_time[0] = 0;    // First process has 0 waiting time

    for (int i = 1; i < n; i++) {
        waiting_time[i] = 0;
        // Add burst times of all previous processes
        for (int j = 0; j < i; j++) {
            waiting_time[i] += burst_time[j];
        }
    }

    // Calculate turnaround time for each process and total times
    cout << "\nProcess\tBurst Time\tWaiting Time\tTurnaround Time" << endl;
    cout << "----------------------------------------------------" << endl;

    for (int i = 0; i < n; i++) {
        turnaround_time[i] = burst_time[i] + waiting_time[i];
        total_waiting_time += waiting_time[i];
        total_turnaround_time += turnaround_time[i];

        cout << "P" << i + 1 << "\t" << burst_time[i] << "\t\t"
             << waiting_time[i] << "\t\t" << turnaround_time[i] << endl;
    }

    return 0;
}

Разберем, что мы добавили:

  1. Два новых массива: waiting_time[20] и turnaround_time[20] для хранения времени ожидания и времени выполнения каждого процесса.
  2. Переменные для отслеживания общего времени ожидания и общего времени выполнения.
  3. Вычисление времени ожидания:
    • У первого процесса время ожидания равно 0.
    • Для каждого последующего процесса время ожидания равно сумме времен выполнения всех предыдущих процессов.
  4. Вычисление времени выполнения:
    • Для каждого процесса время выполнения = время выполнения + время ожидания.
  5. Отформатированная таблица для отображения результатов.

Скомпилируем и запустим нашу обновленную программу:

g++ fcfs.cpp -o fcfs
./fcfs

Попробуйте ввести те же данные, что и раньше:

3
5
9
4

Вы должны увидеть вывод, похожий на следующий:

FCFS Scheduling Algorithm Implementation
----------------------------------------

Enter the number of processes (maximum 20): 3

Enter the Burst Time for each process:
Process P1: 5
Process P2: 9
Process P3: 4

Process Burst Time      Waiting Time    Turnaround Time
----------------------------------------------------
P1      5               0               5
P2      9               5               14
P3      4               14              18

Проанализируем результаты:

  • P1: Время ожидания = 0, Время выполнения = 5 (его время выполнения).
  • P2: Время ожидания = 5 (время выполнения P1), Время выполнения = 14 (5 + 9).
  • P3: Время ожидания = 14 (сумма времен выполнения P1 и P2), Время выполнения = 18 (14 + 4).

Это подтверждает, что наши вычисления времени ожидания и времени выполнения работают правильно. На следующем этапе мы вычислим средние времена и отобразим итоговые результаты.

Вычисление средних времен и отображение итоговых результатов

На этом последнем этапе мы вычислим среднее время ожидания и среднее время выполнения для всех процессов. Эти средние значения являются важными показателями для оценки эффективности алгоритма планирования.

Давайте модифицируем наш файл fcfs.cpp, чтобы добавить эти вычисления и завершить нашу программу:

#include <iostream>
#include <iomanip> // For formatted output

using namespace std;

int main() {
    cout << "FCFS Scheduling Algorithm Implementation" << endl;
    cout << "----------------------------------------" << endl;

    // Variables declaration
    int n;                      // Number of processes
    int burst_time[20];         // Array to store burst time of each process
    int waiting_time[20];       // Array to store waiting time of each process
    int turnaround_time[20];    // Array to store turnaround time of each process
    int total_waiting_time = 0;
    int total_turnaround_time = 0;
    float avg_waiting_time = 0.0;
    float avg_turnaround_time = 0.0;

    // Get the number of processes from the user
    cout << "\nEnter the number of processes (maximum 20): ";
    cin >> n;

    // Input validation
    if (n <= 0 || n > 20) {
        cout << "Invalid number of processes. Please enter a value between 1 and 20." << endl;
        return 1;
    }

    // Get burst time for each process
    cout << "\nEnter the Burst Time for each process:" << endl;
    for (int i = 0; i < n; i++) {
        cout << "Process P" << i + 1 << ": ";
        cin >> burst_time[i];

        // Input validation for burst time
        if (burst_time[i] <= 0) {
            cout << "Burst time must be a positive integer. Please restart the program." << endl;
            return 1;
        }
    }

    // Calculate waiting time for each process
    waiting_time[0] = 0;    // First process has 0 waiting time

    for (int i = 1; i < n; i++) {
        waiting_time[i] = 0;
        // Add burst times of all previous processes
        for (int j = 0; j < i; j++) {
            waiting_time[i] += burst_time[j];
        }
    }

    // Calculate turnaround time for each process and total times
    cout << "\nProcess\tBurst Time\tWaiting Time\tTurnaround Time" << endl;
    cout << "----------------------------------------------------" << endl;

    for (int i = 0; i < n; i++) {
        turnaround_time[i] = burst_time[i] + waiting_time[i];
        total_waiting_time += waiting_time[i];
        total_turnaround_time += turnaround_time[i];

        cout << "P" << i + 1 << "\t" << burst_time[i] << "\t\t"
             << waiting_time[i] << "\t\t" << turnaround_time[i] << endl;
    }

    // Calculate average waiting time and average turnaround time
    avg_waiting_time = (float)total_waiting_time / n;
    avg_turnaround_time = (float)total_turnaround_time / n;

    // Display the results with two decimal places
    cout << fixed << setprecision(2);
    cout << "\nAverage Waiting Time: " << avg_waiting_time << " time units" << endl;
    cout << "Average Turnaround Time: " << avg_turnaround_time << " time units" << endl;

    // Visual representation of the FCFS schedule (Gantt chart in text)
    cout << "\nGantt Chart:" << endl;
    cout << " ";
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < burst_time[i]; j++) {
            cout << "--";
        }
    }
    cout << endl << "|";

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < burst_time[i] - 1; j++) {
            cout << " ";
        }
        cout << "P" << i + 1;
        for (int j = 0; j < burst_time[i] - 1; j++) {
            cout << " ";
        }
        cout << "|";
    }

    cout << endl << " ";
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < burst_time[i]; j++) {
            cout << "--";
        }
    }

    cout << endl;
    cout << "0";
    int current_time = 0;
    for (int i = 0; i < n; i++) {
        current_time += burst_time[i];
        for (int j = 0; j < burst_time[i] * 2 - 1; j++) {
            cout << " ";
        }
        if (current_time < 10) cout << " ";
        cout << current_time;
    }
    cout << endl;

    return 0;
}

Разберем, что мы добавили:

  1. Две новые переменные: avg_waiting_time и avg_turnaround_time для хранения средних времен.
  2. Вычисления средних времен:
    • Среднее время ожидания = Общее время ожидания / Количество процессов
    • Среднее время выполнения = Общее время выполнения / Количество процессов
  3. Отформатированный вывод для отображения средних времен с двумя знаками после запятой.
  4. Простая текстовая диаграмма Ганта для визуального представления расписания FCFS:
    • Каждый процесс представлен своим идентификатором (P1, P2 и т.д.)
    • Ширина каждого блока процесса пропорциональна его времени выполнения
    • Метки времени показаны внизу

Скомпилируем и запустим нашу окончательную программу:

g++ fcfs.cpp -o fcfs
./fcfs

Попробуйте ввести те же данные, что и раньше:

3
5
9
4

Вы должны увидеть вывод, похожий на следующий:

FCFS Scheduling Algorithm Implementation
----------------------------------------

Enter the number of processes (maximum 20): 3

Enter the Burst Time for each process:
Process P1: 5
Process P2: 9
Process P3: 4

Process Burst Time      Waiting Time    Turnaround Time
----------------------------------------------------
P1      5               0               5
P2      9               5               14
P3      4               14              18

Average Waiting Time: 6.33 time units
Average Turnaround Time: 12.33 time units

Gantt Chart:
 --------------------
|   P1    |    P2    |  P3  |
 --------------------
0         5         14     18

Рассмотрим результаты:

  • Среднее время ожидания: (0 + 5 + 14) / 3 = 6.33 единицы времени
  • Среднее время выполнения: (5 + 14 + 18) / 3 = 12.33 единицы времени

Диаграмма Ганта визуально показывает, как процессы запланированы во времени:

  • P1 выполняется с времени 0 до 5
  • P2 выполняется с времени 5 до 14
  • P3 выполняется с времени 14 до 18

Это завершает нашу реализацию алгоритма планирования FCFS. Вы можете поэкспериментировать с разными количествами процессов и временами выполнения, чтобы увидеть, как это влияет на среднее время ожидания и время выполнения.

Резюме

В этом лабораторном занятии мы успешно реализовали алгоритм планирования процессора "Первым пришел - первым обслужен" (First Come First Serve, FCFS) на языке C++. Вот основные концепции и навыки, которые вы изучили:

  1. Основы алгоритма FCFS: Понимание того, как процессы планируются в порядке их поступления.

  2. Вычисление показателей производительности:

    • Время ожидания: Время, в течение которого процесс ожидает начала выполнения.
    • Время выполнения: Общее время от подачи процесса до его завершения.
    • Среднее время ожидания и среднее время выполнения: Ключевые показатели производительности алгоритмов планирования.
  3. Концепции программирования на C++:

    • Массивы для хранения информации о процессах.
    • Циклы для итеративных вычислений.
    • Операции ввода/вывода с проверкой корректности данных.
    • Отформатированный вывод для более наглядного представления данных.
  4. Техники визуализации: Создание текстовой диаграммы Ганта для визуального представления временного графика планирования.

Алгоритм FCFS прост в понимании и реализации, но не всегда обеспечивает оптимальную производительность. Он может привести к "эффекту конвоя", когда короткие процессы вынуждены ждать за длинными процессами, что увеличивает среднее время ожидания.

Эта реализация служит основой для понимания более сложных алгоритмов планирования, таких как "Самый короткий процесс первым" (Shortest Job First, SJF), планирование по приоритету и "Круговой алгоритм" (Round Robin, RR), которые направлены на оптимизацию различных аспектов планирования процессов.