- •Лабораторная работа № 5. Потоки и процессы в Microsoft Visual Studio.
- •Методы решения дифференциального уравнения
- •Лабораторная работа № 6. Динамически подключаемые библиотеки
- •6.1. Цель работы
- •6.2. Теоретические сведения
- •Лабораторная работа № 7 Обработка исключительных ситуаций в Visual c#
- •7.1. Цель работы
- •7.2. Теоретические сведения
- •1) Контролируемый блок – составной оператор, предваряемый ключе-
- •Организация удаленного взаимодействия при помощи технологии .Net
- •8.1. Цель работы
- •8.2. Теоретические сведения
Лабораторная работа № 5. Потоки и процессы в Microsoft Visual Studio.
5.1. Цель работы
Научиться писать многозадачные приложения с использованием средств Microsoft Visual Studio.
5.2. Теоретические сведения
Потоки – это наборы команд, которые могут получать время процессора. Время процессора выделяется квантами. Квант времени – это минимальный ин-
тервал, в течение которого только один поток использует процессор. Как ми- нимум, каждый процесс имеет хотя бы один (главный) поток, но ОС, начиная с Windows95 и NT, позволяют в рамках процесса запустить произвольное число потоков. Существует две модели применения потоков – асимметричная и сим- метричная.
В рамках асимметричной модели потоки решают различные задачи и, как
правило, не разделяют совместные ресурсы. В симметричной модели потоки выполняют одну и ту же работу, разделяют одни ресурсы и исполняют один код.
Исполняемая программа в терминологии операционной системы обозна- чается как «процесс». Процесс состоит из виртуальной памяти, исполняемого кода, потоков и данных. Процесс может содержать много потоков, но обяза- тельно по крайней мере содержит хотя бы один. Потоку, как правило, предос-
тавляется минимум ресурсов, он зависит от процесса, который и распоряжается виртуальной памятью, кодом, данными, файлами и другими ресурсами ОС.
При работе с потоками могут возникать две следующих проблемы – гон- ки и тупики. Ситуация гонок возникает, когда два или более потока пытаются получить доступ к общему ресурсу и изменить его состояние. Например, По- ток1 получил доступ к ресурсу и изменил его в своих интересах; затем активи-
зировался Поток2 и модифицировал этот же ресурс до завершения Потока1. Поток1 полагает, что ресурс остался в том же состоянии, в каком был до пере- ключения. В зависимости от того, когда именно был изменен ресурс, результа- ты могут варьироваться – иногда код будет исполняться нормально, а иногда нет, т.к. планировщик ОС может запускать и останавливать потоки в любое время. Ситуация тупиков возникает, когда поток ожидает ресурс, который в
данный момент принадлежит другому потоку. Например, Поток1 захватывает объект А и , для того чтобы продолжить работу, ждет возможности захватить объект Б. В то же время Поток2 захватывает объект Б и ждет возможности за- хватить объект А. Таким образом, оба потока будут заблокированы. Возникно- вения как ситуаций гонок, так и тупиков можно избежать, если пользоваться средствами синхронизации потоков.
Когда создается поток, то ему назначается приоритет, соответствующий
приоритету породившего его процесса. Процессы имеют следующие приорите-
ты – реального времени (Real Time), высокий (High), нормальный (Normal), фо- новый (Idle).
Поддержка многопоточности осуществляется в .NET в основном с помо-
щью пространства имен System.Threading. Некоторые из типов этого про- странства имен приведены в таблице 5.1.
Типы пространства имен System.Threading
Таблица 5.1
Тип |
Описание |
Interlocked |
Класс, обеспечивающий синхронизированный дос- туп к переменным, которые используются в разных потоках |
Monitor |
Класс, обеспечивающий синхронизацию доступа к объектам |
Mutex |
Класс-примитив синхронизации, который использу- ется также для синхронизации между процессами |
ReaderWriterLock |
Класс, определяющий блокировку, поддерживаю- щую один доступ на запись и несколько – на чтение |
Thread |
Класс, который создает поток, устанавливает его приоритет, получает информацию о состоянии |
ThreadPool |
Класс, используемый для управления набором взаимосвязанных потоков – пулом потоков |
Timer |
Класс, определяющий механизм вызова заданного метода в заданные интервалы времени для пула по- токов |
WaitHandle |
Класс, инкапсулирующий объекты синхронизации, которые ожидают доступа к разделяемым ресурсам |
IOCompletionalCallback |
Класс, получающий сведения о завершении опера- ции ввода-вывода |
ThreadStart |
Делегат, представляющий метод, который должен быть выполнен при запуске потока |
TimerCallback |
Делегат, представляющий метод, обрабатывающий вызовы от класса Timer |
WaitCallback |
Делегат, представляющий метод для элементов классов ThreadPool |
ThreadPrority |
Перечисление, описывающее приоритет потока |
ThreadState |
Перечисление, описывающее состояние потока |
Первичный поток создается автоматически. Для запуска вторичных по- токов используется класс Thread. Основные элементы класса Thread приве- дены в таблице 5.2.
Основные элементы класса Thread
Таблица 5.2
Элемент |
Вид |
Описание |
CurrentThread |
Статическое свойство |
Возвращает ссылку на выполняющийся по- ток (только для чтения) |
IsAlive |
Свойство |
Возвращает true или false в зависимо- сти от того запущен поток или нет |
IsBackground |
Свойство |
Возвращает или устанавливает значение, которое показывает, является ли этот поток фоновым |
Name |
Свойство |
Установка текстового имени потока |
Priority |
Свойство |
Получить/установить приоритет потока (используется значение перечисления ThreadPriority |
ThreadState |
Свойство |
Возвращает состояние потока (использует- ся значение перечисления ThreadState) |
Abort |
Метод |
Генерирует исключение ThreadAbor- tException. Вызов этого метода обычно завершает работу потока |
GetData, SetData |
Статические методы |
Возвращает (устанавливает) значение для указанного слота в текущем потоке |
GetDomain, GetDo- mainID |
Статические методы |
Возвращает ссылку на домен приложения (идентификатор домена приложения), в рамках которого работает поток |
GetHashCode |
метод |
Возвращает хеш-код для потока |
Sleep |
Статический метод |
Приостанавливает выполнение текущего потока на заданное количество миллисе- кунд |
Start |
Метод |
Начинает выполнение потока, определен- ного делегатом ThreadStart |
Suspend |
Метод |
Приостанавливает выполнение потока. Ес- ли выполнение потока уже приостановле- но, то игнорируется |
Resume |
Метод |
Возобновляет работу после приостановки потока |
Join |
Метод |
Блокирует вызывающий поток до заверше- ния другого потока или указанного проме- жутка времени |
Interrupt |
Метод |
Прерывает работу текущего потока |
При создании объекта-потока ему передается делегат, определяющий ме- тод, выполнение которого выделяется в отдельный поток:
Thread t = new Thread (new ThreadStart (имя_метода)); После создания потока заданный метод начинает в нем свою работу, а первичный поток продолжает выполняться. В листинге 5.1 приведен пример
одновременной работы двух потоков.
Листинг 5.1. Создание вторичного потока
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static public void Hedgehog()
// метод для вторичного потока
{
for (int i = 0; i < 6; ++i)
{
Console.WriteLine(i);Thread.Sleep(1000);
}
}
static void Main()
{
Console.WriteLine("Первичный поток" +
Thread.CurrentThread.GetHashCode());
Thread ta = new Thread(newThreadStart(Hedgehog)); Console.WriteLine("Вторичный поток" +
ta.GetHashCode());
ta.Start();
for (int i = 0; i > -6; --i)
{
Console.Write(" " +i);Thread.Sleep(400);
}
}
}
}
Так как оба потока работают одновременно, то при использовании ими
одного и того же ресурса возникнет некорректная работа программы. Поэтому такой способ распараллеливания вычислений имеет смысл только для работ с различными ресурсами. Возможна также работа нескольких потоков, которые будут совместно использовать один и тот же код (листинг 5.2).
Листинг 5.2. Потоки, использующие один объект
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Class1
{
public void Do()
{
for (int i = 0; i < 4; ++i)
{
Console.Write(" " + i); Thread.Sleep(3);
}
}
}
class Program
{
static void Main()
{
Class1 a = new Class1(); Thread t1=new Thread (new
ThreadStart(a.Do));
t1.Name ="Second"; Console.WriteLine("Поток"+t1.Name); t1.Start();
Thread t2=new Thread (new
ThreadStart(a.Do)); t2.Name="Third"; Console.WriteLine("Поток"+t2.Name); t2.Start();
}
}
}
Для того чтобы блок кода мог использоваться в каждый момент времени
только одним потоком, применяется оператор lock, имеющий следующий формат:
lock (выражение) блок_операторов
Выражение определяет объект, который требуется заблокировать. Для
обычных методов в качестве выражения используется ключевое слово this, для статических – typeof(класс). Блок операторов задает критическую сек- цию кода, которую требуется заблокировать.
5.3. Программа работы
Написать программу, запускающую два потока и позволяющую получать решение дифференциальных уравнений первого порядка. Решение дифферен- циальных уравнений должно записываться в файл. В двух потоках должны реа- лизовываться различные варианты решения дифференциального уравнения в зависимости от номера варианта:
-
1.
1 и 2
6. 2и 13
11. 2 и 11
2.
1 и 3
7. 12 и 13
12. 10 и 11
3.
1 и 12
8. 1 и 14
13. 10 и 12
4.
2 и 12
9. 2 и 15
14. 1 и 12
5. 1 и 13 10. 1 и 11 15. 7 и 13
Метод решения дифференциальных уравнений взять из таблицы 5.3
Таблица 5.3