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

Синхронизацией работы потоков называется обеспечение корректной работы нескольких потоков с общими (разделяемыми) данными или ресурсами.

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

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

Средство блокировки встроено в язык С#, поэтому доступ ко всем объектам может быть синхронизирован. Синхронизация поддерживается ключевым словом lock.

Формат использования инструкции lock таков:

lock(object)

{

// Инструкции, подлежащие блокировки.

}

Здесь параметр object представляет собой ссылку на синхронизируемый объект.

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

static void Min(int a, int b)

{

:

},

Тогда обращение к этой функции с применением блокировки:

lock(typeof(CA)) CA.Min(x,y);

Рассмотрим пример многопоточного приложения под Windows. В момент запуска приложения в окне приложения появляется десять “шаров”. Координата X всех шаров в момент появления равна нулю, а координата Y рассчитывается как величина равная 10*j, где j порядковый номер шарика. Шарики сразу же начинают двигаться вниз под углом 45 градусов с разными скоростями. Скорость первого шарика принимается за единицу, скорости всех последующих шаров равны скорости первого шарика умноженной на номер шарика. Шарики движутся в области ограниченной координатами 200 на 200 пикселей, отражаясь от границ области по законам физики. Пересчет координат шариков должен осуществляться потоковой функцией. Окно приложения содержит кнопку, при щелчке на которую потоки завершают свою работу, а шарики исчезают с экрана.

Пример 3:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Threading;

namespace Balls

{

public partial class Form1 : Form

{

class Ball

{

int x, y; // координаты

int dx, dy; //приращение координат-определяет скорость

int w, h; //ширина высота шарика

public bool live; // признак жизни

public delegate void DlTp();// Объявление типа (делегат) и

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

// с помощью ее вызова функции Invalidate()для главного потока

public DlTp dl;

public Thread thr; //Создание ссылки на потоковый объект

// потоковая функция

void FnThr()

{

while (live)

{ //здесь отражемся от границ области

if (x < 0 || x > 200) dx = -dx;

if (y < 0 || y > 200) dy = -dy;

//здесь пересчитываем координаты

x += dx;

y += dy;

Thread.Sleep(100);//спим

dl(); //вызываем с помощью делегата Invalidate()

}

w = h = 0; //схлопываем шарик

dl(); //вызываем с помощью делегата Invalidate()

}

//функция рисования шарика

public void DrawBall(Graphics dc)

{

dc.DrawEllipse(Pens.Magenta, x, y, w, h);

}

//конструктор класса

public Ball(int xn, int yn, int wn, int hn, int dxn, int dyn)

{

x = xn; y = yn; w = wn; h = hn; dx = dxn; dy = dyn;//инициализируем

thr = new Thread(new ThreadStart(FnThr)); //создаем потоковый объект

live = true; //устанавливаем признак жизни

thr.Start(); //запускаем поток

}

}

Ball[] bl = new Ball[10];//массив пустых ссылок типа Ball

public Form1()

{

InitializeComponent();

for (int j = 0; j < bl.Length; j++)

{

//создаем потоковые объекты

bl[j] = new Ball(j, j * 10, 10, 10, j + 1, j + 1);

//подписываемся на событие

bl[j].dl += new Ball.DlTp(Invalidate);

}

}

private void Form1_Paint(object sender, PaintEventArgs e)

{

for (int j = 0; j < bl.Length; j++)

{

bl[j].DrawBall(e.Graphics);//рисуем

}

 

}

private void button1_Click(object sender, EventArgs e)

{

for (int j = 0; j < bl.Length; j++)

{

bl[j].live = false;// Уничтожаем потоки

}

}

 

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{

for (int j = 0; j < bl.Length; j++)

{

bl[j].live = false;//уничтожаем потоки

}

}

}

}

Скомпилируйте и выполните приложение. Проанализируйте работу приложения.


 

Вопросы:

1. Объектом, какого класса является поток?

2. Чем определяется сигнатура заголовка потоковой функции?

3. Какова последовательность создания потока и запуск его на выполнение?

4. Каким образом можно установить или прочесть имя потока?

5. С помощью какого свойства можно узнать находится ли поток в активном состоянии?

6. Каким образом можно приостановить работу потока на заданное время?

7. С помощью какого метода можно дождаться завершения работы потока?

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

9. Какой метод служит для аварийного завершения работы потоков?

10. Что называется синхронизацией работы потоков?

11. Каким образом обеспечивается синхронизация работы потоков?

12. Что лежит в основе синхронизации потоков?

13. Каким образом можно применить защиту блокировкой к статическому методу класса?

 

Задания:

1. В приложение по примеру 3 добавить редактор TextBox и две кнопки. При щелчке на первую кнопку шарик с номером, указанным в TextBox останавливатся, а при щелчке на вторую продолжает движение.

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

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

4. В приложение по примеру № 3 добавить вертикальную область. Внутри области может находиться только один шарик, другие шарики ожидают, пока область не освободится. Применить синхронизацию потоков.

5. В приложении по примеру № 3 выделить функцию пересчета координат в отдельный класс. Создать единственный объект этого класса. Все потоковые объекты должны обращаться к функции этого объекта для пересчета координат. Применить синхронизацию потоков.

6. Создать консольное приложение. В нем два потока обращаются к одному и тому же объекту. Метод этого объекта принимает в качестве параметра массив и возвращает сумму элементов массива. В процессе расчета суммы печатается промежуточная сумма и имя потока, для которого производится расчет. Потоки по окончанию работы печатают полученный результат работы (сумму) и свое имя.

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

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

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

10. Создать Windows приложение. Четыре потока обращаются к статическому методу класса, для рисования линии. Метод принимает координаты начала и конца линии. . Каждый поток должен с помощью этого объекта нарисовать замкнутую фигуру, каждый в своей области экрана.

Лабораторная работа №1. 4

Структура консольного приложения. 4

Лабораторная работа №2. 14

Классы, член данные и член функции класса. 14

Методы.. 16

Свойства. 18

Индексаторы.. 20

Лабораторная работа № 3. 26

Конструкторы, поля только для чтения, вызов конструкторов. 26

Конструктор с аргументами. 28

Поля только для чтения. 30

Вызов конструкторов из других конструкторов. 31

Лабораторная работа №4. 38

Делегаты и события. 38

События. 42

Лабораторная работа № 5. 49

Windows − приложение. 49

Лабораторная работа № 6. 57

Простейшие графические возможности. 57

Структура Size. 58

Структура Point 58

Структура Rectangle. 60

Представление цвета. 61

Кисти и перья. 63

Рисование линий и фигур. 65

Рисование текста. 68

Перерисовка окна приложения. 69

Лабораторная работа №7. 74

Создание меню.. 74

Лабораторная работа №8. 87

Потоки. 87

Создание потока. 87

Остановка и возобновление работы потоков. 92

Синхронизация работы потоков. 95