Подсистема управления процессами

Министерство транспорта РФ

Федеральное агентство железнодорожного транспорта

ГОУ ВПО "ДВГУПС"

Кафедра: "Информационные технологии и системы"





















КУРСОВАЯ РАБОТА

на тему: "Подсистема управления процессами"





	Выполнил: Шолков И.Д.

	группа 230

	Проверил: Решетникова О.В.

















Хабаровск 2010


Оглавление



Введение

1. Описание программы

	1.1 Функциональное назначение

	1.2 Технические средства, используемые при создании программы

	1.3 Многопоточность и многопроцессорность

	1.4 Приоритеты потоков и процессов

	1.5 Способы синхронизации потоков

	1.3 Логическая структура программы

2. Руководство пользователя по работе с программой

	2.1 Общие сведения и назначение программы

	2.2 Графический интерфейс

	2.3 Работа с программой

	2.4 Основные характеристики программы Process Manager

Заключение

Список литературы

Приложение




Введение



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

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

В данной курсовой работе необходимо реализовать подсистему управления процессами с невытесняющей многозадачностью, с алгоритмом планирования на основах приоритетов, с постоянной длительностью кванта[1].




1. Описание программы



1.1 Функциональное назначение



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

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



1.2 Технические средства, используемые при создании программы



Многопоточность и многопроцессорность

C# поддерживает параллельное выполнение кода через многопоточность. Поток – это независимый путь исполнения, способный выполняться одновременно с другими потоками.

Программа на C# запускается как единственный поток, автоматически создаваемый CLR и операционной системой ("главный" поток), и становится многопоточной при помощи создания дополнительных потоков.

Управление многопоточностью осуществляет планировщик потоков, эту функцию CLR обычно делегирует операционной системе. Планировщик потоков гарантирует, что активным потокам выделяется соответствующее время на выполнение, а потоки, ожидающие или блокированные, к примеру, на ожидании эксклюзивной блокировки, или пользовательского ввода – не потребляют времени CPU.

На однопроцессорных компьютерах планировщик потоков использует квантование времени – быстрое переключение между выполнением каждого из активных потоков. Это приводит к непредсказуемому поведению, как в самом первом примере, где каждая последовательность символов ‘X’ и ‘Y’ соответствует кванту времени, выделенному потоку. В Windows XP типичное значение кванта времени – десятки миллисекунд – выбрано как намного большее, чем затраты CPU на переключение контекста между потоками (несколько микросекунд).

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

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

Все потоки одного приложения логически содержатся в пределах процесса – модуля операционной системы, в котором исполняется приложение.

В некоторых аспектах потоки и процессы схожи – например, время разделяется между процессами, исполняющимися на одном компьютере, так же, как между потоками одного C#-приложения. Ключевое различие состоит в том, что процессы полностью изолированы друг от друга. Потоки разделяют память (кучу) с другими потоками этого же приложения. Благодаря этому один поток может поставлять данные в фоновом режиме, а другой – показывать эти данные по мере их поступления.

Приоритеты потоков и процессов

Свойство Priority определяет, сколько времени на исполнение будет выделено потоку относительно других потоков того же процесса. Существует 5 градаций приоритета потока:enum ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest }

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

Установка приоритета потока на максимум еще не означает работу в реальном времени (real-time), так как существуют еще приоритет процесса приложения. Чтобы работать в реальном времени, нужно использовать класс Process из пространства имен System.Diagnostics для поднятия приоритета процесса .

От ProcessPriorityClass.High один шаг до наивысшего приоритета процесса – Realtime. Устанавливая приоритет процесса в Realtime, вы говорите операционной системе, что хотите, чтобы ваш процесс никогда не вытеснялся. Если ваша программа случайно попадет в бесконечный цикл, операционная система может быть полностью заблокирована. Спасти вас в этом случае сможет только кнопка выключения питания. По этой причине ProcessPriorityClass.High считается максимальным приоритетом процесса, пригодным к употреблению.

Если real-time приложение имеет пользовательский интерфейс, может быть не желательно поднимать приоритет его процесса, так как обновление экрана будет съедать чересчур много времени CPU – тормозя весь компьютер, особенно если UI достаточно сложный.

Способы синхронизации потоков

Оператор lock (aka Monitor.Enter/Monitor.Exit) – один из примеров конструкций синхронизации потоков. Lock является самым подходящим средством для организации монопольного доступа к ресурсу или секции кода, но есть задачи синхронизации (типа подачи сигнала начала работы ожидающему потоку), для которых lock будет не самым адекватным и удобным средством.

В Win32 API имеется богатый набор конструкций синхронизации, и они доступны в .NET Framework в виде классов EventWaitHandle, Mutex и Semaphore. Некоторые из них практичнее других: Mutex, например, по большей части дублирует возможности lock, в то время как EventWaitHandle предоставляет уникальные возможности сигнализации.

Все три класса основаны на абстрактном классе WaitHandle, но весьма отличаются по поведению. Одна из общих особенностей – это способность именования, делающая возможной работу с потоками не только одного, но и разных процессов.

EventWaitHandle имеет два производных класса – AutoResetEvent и ManualResetEvent (не имеющие никакого отношения к событиям и делегатам C#). Обоим классам доступны все функциональные возможности базового класса, единственное отличие состоит в вызове конструктора базового класса с разными параметрами.

В части производительности, все WaitHandle обычно исполняются в районе нескольких микросекунд. Это редко имеет значение с учетом контекста, в котором они применяются.

AutoResetEvent – наиболее часто используемый WaitHandle-класс и основная конструкция синхронизации, наряду с lock.

AutoResetEvent очень похож на турникет – один билет позволяет пройти одному человеку. Приставка "auto" в названии относится к тому факту, что открытый турникет автоматически закрывается или "сбрасывается" после того, как позволяет кому-нибудь пройти. Поток блокируется у турникета вызовом WaitOne (ждать (wait) у данного (one) турникета, пока он не откроется), а билет вставляется вызовом метода Set. Если несколько потоков вызывают WaitOne, за турникетом образуется очередь. Билет может "вставить" любой поток – другими словами, любой (неблокированный) поток, имеющий доступ к объекту AutoResetEvent, может вызвать Set, чтобы пропустить один блокированный поток.

Если Set вызывается, когда нет ожидающих потоков, хэндл будет находиться в открытом состоянии, пока какой-нибудь поток не вызовет WaitOne. Эта особенность помогает избежать гонок между потоком, подходящим к турникету, и потоком, вставляющим билет ("опа, билет вставлен на микросекунду раньше, очень жаль, но вам придется подождать еще сколько-нибудь!"). Однако многократный вызов Set для свободного турникета не разрешает пропустить за раз целую толпу – сможет пройти только один человек, все остальные билеты будут потрачены впустую.

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

Метод Reset обеспечивает закрытие открытого турникета, безо всяких ожиданий и блокировок.

AutoResetEvent может быть создан двумя путями. Во-первых, с помощью своего конструктора:EventWaitHandle wh = new AutoResetEvent(false);

Если аргумент конструктора true, метод Set будет вызван автоматически сразу после создания объекта.

Другой метод состоит в создании объекта базового класса, EventWaitHandle:EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.Auto);

Конструктор EventWaitHandle также может использоваться для создания объекта ManualResetEvent (если задать в качестве параметра EventResetMode.Manual).

Метод Close нужно вызывать сразу же, как только WaitHandle станет не нужен – для освобождения ресурсов операционной системы. Однако если WaitHandle используется на протяжении всей жизни приложения (как в большинстве примеров этого раздела), этот шаг можно опустить, так как он будет выполнен автоматически при разрушении домена приложения.

ManualResetEvent – это разновидность AutoResetEvent. Отличие состоит в том, что он не сбрасывается автоматически, после того как поток проходит через WaitOne, и действует как шлагбаум – Set открывает его, позволяя пройти любому количеству потоков, вызвавших WaitOne. Reset закрывает шлагбаум, потенциально накапливая очередь ожидающих следующего открытия.

Эту функциональность можно эмулировать при помощи булевой переменной "gateOpen" (объявленной как volatile) в комбинации со "spin-sleeping" – повторением проверок флага и ожидания в течении короткого промежутка времени.

ManualResetEvent может использоваться для сигнализации о завершении какой-либо операции или инициализации потока и готовности к выполнению работы[2].



1.3 Логическая структура программы



Основу программы составляет абстрактный класс Betaproc. В нем реализована абстрактная модель процесса, без спецификации выполняемых действий, с набором переменных и методов общих для всех процессов. Три процесса sinProc, FibbonProc и ProcRandom являются производными от этого класса и в каждом из них реализован лишь методы возвращающие тип процесса и сам метод выполняемый процессом. При этом каждый метод Base, в котором находится исполняемый код, имеет в своем теле общий для всех хэндл, который позволяет выполнять код лишь одному процессу, когда другие становятся в очередь и получают свое время на выполнение пропорционально приоритету. В момент начала работы стартует таймер, который обеспечивает одинаковый квант времени в 3 секунды для каждого процесса.

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




Руководство пользователя по работе с программой



2.1 Общие сведения и назначение программы



Программа написана в среде Visual Studio 2008 на языке C# и представляет собой менеджер управления процессами, построенный на современных средствах управления, с интуитивно понятным графическим интерфейсом. Программа является полностью автономной и не требует установки другого программного обеспечения. Вся справочная информация хранится в настоящем Руководстве и Техническом Проекте. В случае сбоев в работе программы необходимо обратиться к Автору для их устранения. В основной части руководства будут описаны возможности программы, описание основных характеристик и особенностей программы.



2.2 Графический интерфейс



После открытия программы пользователю предоставляется графический интерфейс.





рис 1.: главное окно программы после запуска


Область "Процесс" позволяет выбрать тот процесс, который нам необходимо запустить. Имеет три пункта: Числа Фибоначчи, Случайные числа и Рекурсивный синус.

Область "Приоритет" позволяет установить приоритет запускаемому процессу. Имеет 5 пунктов: Низкий, Ниже среднего, Средний, Выше среднего, Высокий.

Кнопка запуск служит для запуска процесса с выбранными параметрами.

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

Номер процесса – показывает порядковый номер процесса

Тип процесса – показывает действие, с которое выполняет данный процесс

Состояние процесса – показывает работает ли процесс в данный момент или нет. Также показывает, если процесс является остановленным, завершенным или только что возобновленным.

Приоритет процесса – показывает приоритет процесса, который был присвоен ему при создании.

Процент процессорного времени – отображает процент используемого процессорного времени.

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

В нижней части окна программы расположены элементы управления для работы с уже запущенными процессами.

Кнопка "Остановить" - останавливает выбранный процесс с возможностью его последующего перезапуска.

Кнопка "Возобновить" - вновь запускает остановленный процесс.

Кнопка "Завершить" - останавливает выбранный процесс без возможности его завершения.

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



2.3 Работа с программой



Запуск процессов выполняется с помощью кнопки "Запустить", однако перед этим следует установить параметры процесса.

Случайное число – процесс генерирует случайное число в интервале от одного до ста и выводит его в поле вывода.

Числа Фибоначчи – генерирует последовательность Фибоначчи, начиная с первого члена, и выводит их в поле вывода. Как только значение чисел последовательности превосходит тысячу – значения сбрасываются до первых членов.

Рекурсивный синус – генерирует значение синуса X. Первоначально X равен 1, позже ему присваиваются посчитанные значения sin(x). Значения, округленные до третьего знака выводятся в поле вывода.

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

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




рис 2: работа программы.



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

Если нам хочется остановить процесс под номером 2, необходимо выбрать вторую строку в таблице процессов и нажать кнопку "Остановить". После выполнения команды окно примет следующий вид:





рис. 3: процесс с Process ID = 2 остановлен.



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

Процесс, который вновь начал работу, но еще ни разу не выполнялся отмечается подписью "Возобновлен" в третьем столбце, как на картинке:





рис. 4: работа процесса с Process ID = 2 возобновлена.



Если мы захотим завершить процесс, под номером 3, необходимо выбрать третью строку в таблице процессов и нажать кнопку "Завершить". Процесс, который завершен уже не может быть запущен вновь. Создайте процесс с такими же параметрами.








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

Для корректного завершения работы программы необходимо просто щелкнуть мышкой на знак крестика в строке заголовка.



2.4 Основные характеристики программы Process Manager



Process Manager – это программа, предназначенная для управления процессами пользователем персонального компьютера. Она работает под управлением операционных систем MS Windows 2000/XP/Vista/7.

Process Manager позволяет формировать списки процессов и выводить результаты их деятельности на экран с последующим сохранением. Стандартными средствами нельзя достичь точных результатов, можно лишь увидеть примерное количество ресурсов процессора и памяти, который процесс использует в данный период времени.

Программа включает в себя набор базовых элементов, каждый из которых позволяет выполнить определенную задачу проекта. После загрузки проекта и запуска процессов значения и параметры работы процессов сразу отображаются на дисплее. Подробное описание работы с программой представлено в первом пункте настоящего документа. Подробное описание логической структуры программы и код программы можно найти в документе "Технический проект автоматизированной	подсистемы для визуализации работы с процессами Process Manager". Программа работает в штатном режиме, однако в случае необходимости может работать круглосуточно и непрерывно. Программа прошла всестороннюю проверку и полностью защищена от сбоев и исключений.




Заключение



Подсистема управления процессами является одной из важнейших частей операционной системы. В этой курсовой работе был представлен один из вариантов его реализации, неприменимый в реальной жизни. Тем не менее, нельзя не отметить, что этот проект весьма упрощен. Подсистема управления процессами, которая реально могла бы стать частью многозадачной операционной системы, требует гораздо большей степени проработанности, уметь работать с прерываниями, разнородными процессами, а к тому же иметь некоторую защиту от внешнего воздействия, ведь умышленное или неумышленное завершение критически важных процессов может привести к краху системы. Но все же, в работе представлена довольно изящная реализация. Главная ее проблема в том, что в ней реализованы не все возможные компоненты, и некоторые моменты регулируются встроенными средствами операционной системой, которая работает на компьютере, в данном случае Windows. При реальном программировании операционной системы, подсистема управления процессами должна быть построена с нуля и иметь определение и описание многих элементов, которые работает в этом проекте по умолчанию [3].




Список литературы



Безбогов, А.А. Безопасность операционных систем : учебное пособие / А.А. Безбогов, А.В. Яковлев, Ю.Ф. Мартемьянов. – М. : "Издательство Машиностроение-1", 2007. – 220 с.

Операционные системы, лекции по операционным системам [Электронный ресурс] / www.osi-ru.ru. - Содержание: Управление процессами; Управление памятью; Управление данными; Управление устройствами

Троелсен, Э. C# и платформа .NET: учебное пособие/ Э.Троелсен. – Спб. : "Питер Пресс", 2007. –796с.




Приложение



Исходный код программы Process Manager



using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading;

using System.Windows.Forms;

using Timer=System.Threading.Timer;

namespace ProcManager

{

abstract class BetaProc

{

protected Thread a;

bool isWorking = false;

public event EventHandler WorkingStateChanged = delegate { };

public bool IsWorking

{

get { return isWorking; }

set

{

isWorking = value;

WorkingStateChanged(this, EventArgs.Empty);

}

}

public void Delete()

{

if (a != null)

{

a.Abort();

a = null;

if (IsWorking == true)

{

if (WaitToStart.Set() == false)

WaitToStart.Set();

}

}

}

public ThreadPriority Prior

{

get { return a.Priority; }

set { a.Priority = value; }

}

public void Stop()

{

a.Abort();

if(isWorking == true)

WaitToStart.Set();

}

private DataGridView data;

public delegate void ChangeStateEventHandler(string msg);

public static event ChangeStateEventHandler change;

public abstract string GetType();

public string GetState()

{

return IsWorking ? "Работает" : "Не работает";

}

public string GetPriority()

{

return a.Priority.ToString();

}

public void ChangeState()

{

if (IsWorking == false)

{

IsWorking = true;

}

else

{

IsWorking = false;

}

}

public abstract void Base();

private Control pReporter;

public DataGridView reporterD

{

get

{

return data;

}

set

{

data = value;

}

}

public Control reporter

{

get

{

return pReporter;

}

set

{

pReporter = value;

}

}

public EventWaitHandle SwaitTostart

{

set

{

WaitToStart = value;

}

}

protected Stopwatch timer = new Stopwatch();

public void Start()

{

a = new Thread(Base);

a.Start();

}

delegate void SetTextDelegate2(string Text);

public static EventWaitHandle WaitToStart;

public void SetText2(string Text)

{

if (reporter.InvokeRequired)

{

SetTextDelegate2 a = new SetTextDelegate2(SetText2);

reporter.Invoke(a, new object[] { Text });

}

else reporter.Text += Text;

}

public void Restart()

{

if(isWorking == true)

ChangeState();

timer = new Stopwatch();

a=new Thread(Base);

a.Start();

timer.Start();

}

}

}

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading;

namespace ProcManager

{

class FibbonProc:BetaProc

{

public readonly string Type = "Числа Фиббоначи";

public override string GetType()

{

return Type;

}

private int FSum = 1;

private int FSum2 = 1;

private int temp = 0;

public override void Base()

{

WaitToStart.WaitOne();

if (IsWorking == false)

ChangeState();

timer.Reset();

timer.Start();

do

{

if (FSum >= 1000)

{

FSum = 1;

FSum2 = 1;

}

temp = FSum;

FSum = FSum + FSum2;

FSum2 = temp;

SetText2(FSum.ToString() + "\r\n");

Thread.Sleep(1110);

}

while (timer.ElapsedMilliseconds <= 3000);

Restart();

WaitToStart.Set();

}

}

}

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading;

namespace ProcManager

{

class ProcRandom:BetaProc

{

Random a = new Random();

private int res;

public readonly string Type = "Случайное число";

public override string GetType()

{

return Type;

}

public override void Base()

{

WaitToStart.WaitOne();

if (IsWorking == false)

ChangeState();

timer.Reset();

timer.Start();

do

{

res = a.Next(100);

SetText2(res.ToString()+"\r\n");

Thread.Sleep(1110);

}

while (timer.ElapsedMilliseconds <= 3000);

Restart();

WaitToStart.Set();

}

}

}

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading;

namespace ProcManager

{

class SinProc:BetaProc

{

private double x = 1;

public readonly string Type = "Синус X";

public override string GetType()

{

return Type;

}

public override void Base()

{

WaitToStart.WaitOne();

if(IsWorking == false)

ChangeState();

timer.Reset();

timer.Start();

do

{

x = Math.Sin(x);

SetText2(Math.Round(x, 3).ToString()+"\r\n");

Thread.Sleep(1110);

}

while (timer.ElapsedMilliseconds <= 3000);

Restart();

WaitToStart.Set();

}

}

}

using System.Collections;

using System.Threading;

using System.Windows.Forms;

using System;

namespace ProcManager

{

class ClassProcManager

{

private BetaProc[] mas = new BetaProc[30];

private DataGridView a;

private int index = 0;

public BetaProc[] ReturnMas()

{

return mas;

}

public int Index()

{

return index;

}

public DataGridView reporterD

{

get

{

return a;

}

set

{

a = value;

}

}

public void AddThread(BetaProc a)

{

if (index < mas.Length)

{

mas[index] = a;

}

else

MessageBox.Show("Слишком много процессов");

}

public void ShowInDataView(BetaProc b)

{

a.Rows.Add(index + 1, b.GetType(), b.GetState(), b.GetPriority());

index++;

}

public void SetWaitProperty(BetaProc b)

{

int i = Array.IndexOf(mas, b);

if((i<0) || (i>a.Rows.Count - 1))

return;

for (int s = 0; s < index; s++)

{

if ((int)a.Rows[s].Cells[0].Value == i+1)

{

DataGridViewRow row = a.Rows[s];

row.Cells[2].Value = b.GetState();

}



}

}

}

}

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading;

using System.Windows.Forms;

namespace ProcManager

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

public int index = 0;

private ClassProcManager manager = new ClassProcManager();

private EventWaitHandle wh1 = new AutoResetEvent(true);

private RadioGroup processType;

private RadioGroup processPriority;

private ThreadPriority[] ProcessPriorities = new ThreadPriority[30];

ThreadPriority HighestPriority = ThreadPriority.Lowest;

/// <summary>

/// Возвращает приоритет процесса

/// </summary>

/// <param name="priority">Tag </param>

/// <returns>Объект из перечисления ThreadPriority</returns>

private ThreadPriority IndexToPriority(int priority)

{

switch (priority)

{

case 0: return ThreadPriority.Lowest;

case 1: return ThreadPriority.BelowNormal;

case 2: return ThreadPriority.Normal;

case 3: return ThreadPriority.AboveNormal;

case 4: return ThreadPriority.Highest;

default: return ThreadPriority.Normal;

}

}

private void button1_Click(object sender, EventArgs e)

{

BetaProc process;

switch (processType.SelectedButton)

{

case 0: process = new FibbonProc();

break;

case 1: process = new ProcRandom();

break;

case 2: process = new SinProc();

break;

default: process = new ProcRandom();

break;

}

process.SwaitTostart = wh1;

process.reporter = richTextBox1;

process.reporterD = dataGridView1;

process.Start();

process.Prior = IndexToPriority(processPriority.SelectedButton);

manager.AddThread(process);

manager.ShowInDataView(process);

process.WorkingStateChanged += new EventHandler(a_WorkingStateChanged);

// расчёт процессорноного времени

if (process.Prior > HighestPriority) HighestPriority = process.Prior;

ProcessPriorities[index] = process.Prior;

if (index >= 1)

{

double FreeProcessorTime = 100;

double TimePerProcess = 100 / (index + 1);

double PriorityWeight = 0;

int HighPriorityProcessCount = 0;

// расчёт для процессов с приоритетом ниже самого большого

for (int i = 0; i < index + 1; i++)

{

if (ProcessPriorities[i] != HighestPriority)

{

switch (ProcessPriorities[i])

{

case ThreadPriority.Lowest: PriorityWeight = 0.2;

break;

case ThreadPriority.BelowNormal: PriorityWeight = 0.4;

break;

case ThreadPriority.Normal: PriorityWeight = 0.6;

break;

case ThreadPriority.AboveNormal: PriorityWeight = 0.8;

break;

}

FreeProcessorTime -= TimePerProcess * PriorityWeight;

dataGridView1.Rows[i].Cells[4].Value = Math.Round(TimePerProcess * PriorityWeight);

}

else HighPriorityProcessCount++;

}

// расчёт для процессов с самым большим приоритетом

for (int i = 0; i < index + 1; i++)

{

if (ProcessPriorities[i] == HighestPriority)

{

dataGridView1.Rows[i].Cells[4].Value = Math.Round(FreeProcessorTime / HighPriorityProcessCount);

}

}

}

else dataGridView1.Rows[0].Cells[4].Value = "100";

index++;

}

void a_WorkingStateChanged(object sender, EventArgs e)

{

BetaProc b = sender as BetaProc;

manager.SetWaitProperty(b);

}

private void Form1_Load(object sender, EventArgs e)

{

manager.reporterD = dataGridView1;

// Заполняем RadioGroup processType и processPriority объектами RadioButton

RadioButton[] processTypeRadioButtons = new RadioButton[3];

for (int i = 0; i < groupBox1.Controls.Count; i++) processTypeRadioButtons[i] = (RadioButton)groupBox1.Controls[i];

RadioButton[] processPriorityRadioButtons = new RadioButton[5];

for (int i = 0; i < groupBox2.Controls.Count; i++) processPriorityRadioButtons[i] = (RadioButton)groupBox2.Controls[i];

processType = new RadioGroup(processTypeRadioButtons);

processPriority = new RadioGroup(processPriorityRadioButtons);

}

private void button2_Click(object sender, EventArgs e)

{

int processID = (int)dataGridView1.SelectedRows[0].Cells[0].Value - 1;

if (processID != -1 && (string)manager.reporterD.Rows[processID].Cells[3].Value != "Завершен")

{

manager.ReturnMas()[processID].Stop();

manager.reporterD.Rows[processID].Cells[2].Value = "Приостановлен";

}

}

private void button3_Click(object sender, EventArgs e)

{

int processID = (int)dataGridView1.SelectedRows[0].Cells[0].Value - 1;

if ((string)manager.reporterD.Rows[processID].Cells[2].Value == "Приостановлен")

{

manager.ReturnMas()[processID].Restart();

manager.reporterD.Rows[processID].Cells[2].Value = "Возобновлен";

}

}

private void button4_Click(object sender, EventArgs e)

{

int processID = (int)dataGridView1.SelectedRows[0].Cells[0].Value - 1;

if (processID != -1)

{

manager.ReturnMas()[processID].Delete();

manager.reporterD.Rows[processID].Cells[2].Value = "Завершен";

}

}

}

}