- •Лабораторная работа №8. Разработка многопоточных приложений
- •1. Цель работы
- •2. Сведения из теории
- •2.1. Общие сведения по работе с потоками
- •2.2. Синхронизация потоков
- •2.3. Взаимодействие потоков
- •3. Пример выполнения работы
- •3.1. Создание потоков
- •3.2. Работа с прямоугольной областью
- •3.3. Синхронизация потоков
- •4. Задание для самостоятельной работы
3. Пример выполнения работы
Задание. Необходимо разработать многопоточное приложение с синхронизацией двух потоков и управлением доступом к общему ресурсу. В каждом потоке осуществляется движение графического объекта (в данном случае, круга) от верхнего края формы к нижнему, после чего потоки завершаются. В качестве общего ресурса выступает прямоугольная область в середине формы. Необходимо скоординировать потоки таким образом, чтобы в каждый момент времени внутри этой области находился только один круг.
Внешний вид работающего приложения приведен на рисунке 8.1.
Рис. 8.1. Пример работающего приложения
3.1. Создание потоков
Прежде всего, для работы с потоками необходимо подключить пространство имен System.Threading.
Для того чтобы создавать в приложении новые потоки, необходимо задать метод, который будет являться точкой входа в поток. Этот метод должен быть типа void и без параметров. В нашем случае именно в этом методе (который здесь назван MoveCircle()) и будет осуществляться движение круга.
В этом методе сначала создается контекст графического устройства и две кисти: одна (красного цвета) для круга, вторая (цвета формы) – для стирания предыдущего изображения круга.
Чтобы два круга в разных потоках не сливались друг с другом, для них указываются разные координаты x. Значения координаты устанавливаются в зависимости от имени потока (свойство Name).
После этого в цикле, пока не достигнут нижний край формы, рисуется очередной круг, поток на некоторое время приостанавливается (иначе движение будет происходить настолько быстро, что увидеть его просто не получится), а затем круг стирается.
После окончания цикла для корректности выводится сообщение о завершении текущего потока. Листинг метода приведен ниже:
private void MoveCircle()
{
//создаем контекст устройства
Graphics g = this.CreateGraphics();
//создаем красную кисть - для круга
Brush b1 = Brushes.Red;
//и кисть цвета формы - для стирания круга
Brush b2 = SystemBrushes.Control;
int x;
//координата x круга будет зависеть от имени потока
if (Thread.CurrentThread.Name == "First")
x = Width / 2 - 30;
else
x = Width / 2 + 30;
//цикл от верхнего до нижнего края формы
for (int y = 10; y < Height - 40; y++)
{
//рисуем круг
g.FillEllipse(b1, x - 10, y - 10, 20, 20);
//"усыпляем" поток на 30 миллисекунд
Thread.Sleep(30);
//стираем круг
g.FillEllipse(b2, x - 10, y - 10, 20, 20);
}
//проверяем корректность завершения потока
MessageBox.Show("Поток " + Thread.CurrentThread.Name + " завершен!");
}
Непосредственное создание потоков можно выполнять в обработчике события Load главной формы. При этом для каждого потока нужно создать объект класса Thread, указав при этом имя метода, который будет точкой входа в поток. Далее следует присвоить потоку имя и запустить его с помощью метода Start(). Код обработчика приведен ниже:
private void Form1_Load(object sender, EventArgs e)
{
//создаем первый поток
//(точка входа в него - метод MoveCircle())
Thread thread1 = new Thread(new ThreadStart(MoveCircle));
//присваиваем потоку имя
thread1.Name = "First";
//аналогично для второго потока
Thread thread2 = new Thread(new ThreadStart(MoveCircle));
thread2.Name = "Second";
//запускаем оба потока
thread1.Start();
thread2.Start();
}