Синхронизация потоков Visual Studio. Занятие 4 Синхронизация потоков Вариант 6 Цель занятия. Изучение средств синхронизации нескольких потоков
Скачать 64.29 Kb.
|
Практическое занятие №4 Синхронизация потоков Вариант 6 Цель занятия. Изучение средств синхронизации нескольких потоков. Задание 1. Задача прошлого практического занятия. Требуется вычислить среднеквадратическое значение 1 млн. чисел. Исходные данные хранятся в файле Data.txt. Недостаток приложения в использовании метода Sleep() в основном потоке для ожидания завершения вторичных потоков, причем время ожидания требуется подбирать. Для устранения указанного недостатка необходимо использовать средства синхронизации. Задание 2. Требуется последовательно увеличивать значение глобальной переменной от начального значения, равного 0, до максимального, равного 16, с помощью четырех одновременно выполняющихся потоков. Проверить реализацию задачи с асинхронной работой потоков. Ввести синхронизацию для монопольного выполнения критического участка функции потоков, связанного с изменением глобальной переменной. Проверить реализацию задачи с использованием синхронизации. Выполнение задания 1 Листинг программы: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.IO; namespace Pr4_1 { class Program { static double Sq = 0; static double s1, s2 = 0; static double[] A = new double[1000000]; static void FirstThread() { System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); int n = A.GetLength(0); int n1 = n / 2; for (int i = 0; i < n1; i++) { s1 = s1 + Math.Pow(A[i], 2); } Console.WriteLine("Время потока FirstThread = " + sw.ElapsedMilliseconds + " мс"); } static void SecondThread() { System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); int n = A.GetLength(0); int n1 = n / 2; for (int i = n1; i < n; i++) { s2 = s2 + Math.Pow(A[i], 2); } Console.WriteLine("Время потока SecondThread = " + sw.ElapsedMilliseconds + " мс"); } static void Main(string[] args) { System.Diagnostics.Stopwatch sw1 = System.Diagnostics.Stopwatch.StartNew(); A = File.ReadAllText(@"E:\УНИВЕР\III курс\ВВ\Пр4\Data.txt").Split().Select(double.Parse).ToArray(); Console.WriteLine("Время инициализации массива A из файла = " + sw1.ElapsedMilliseconds + " мс"); int n = A.GetLength(0); // размер массива Thread thread1 = new Thread(new ThreadStart(FirstThread)); Thread thread2 = new Thread(new ThreadStart(SecondThread)); System.Diagnostics.Stopwatch sw2 = System.Diagnostics.Stopwatch.StartNew(); thread1.Start(); thread2.Start(); // ожидание завершения выполнения потоков thread1.Join(); thread2.Join(); Console.WriteLine("Время обработки массива = " + sw2.ElapsedMilliseconds + " мс"); Sq = Math.Sqrt((s1 + s2) / n); Console.WriteLine("Среднеквадратичное n = " + n + " элементов файла = " + Sq); Console.ReadLine(); } } } Результат: Рис. 4.1 Результат выполнения работы Вывод: Воспользовавшись средствами синхронизации, устранили недостаток прошлого приложения (Pr3_2) в использовании метода Sleep() в основном потоке для ожидания завершения вторичных потоков, причем время ожидания требуется подбирать. Выполнение задания 2 Листинг программы последовательного увеличения значения глобальной переменной CommonCount с помощью четырех одновременно запускаемых потоков: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace Pr4_2 { class Program { static int CommonCount = 0; static Object LockObj = new Object(); static void ThreadFunc() { int i, Id; for (int j = 1; j <= 4; j++) { i = CommonCount; i++; Thread.Sleep(1); CommonCount = i; Id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine("Thread Id {0}, i = {1}", Id, i); } } static void Main(string[] args) { for (int i = 0; i < 4; ++i) { new Thread(new ThreadStart(ThreadFunc)).Start(); Thread.Sleep(1); } Console.WriteLine("CommonCount = {0}", CommonCount); Console.ReadLine(); } } } Результат: Рис. 4.2 Асинхронная работа четырех потоков Вывод: Потоки с идентификаторами 3, 4, 5 и 6 выполняют функцию ThreadFunc() не согласовано так, что для изменения CommonCount могут использоваться значения без учета изменений внесенных другими потоками. Листинг программы с синхронизацией работы потоков: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace Pr4_3 { class Program { static int CommonCount = 0; static Object LockObj = new Object(); static void ThreadFunc() { int i, Id; for (int j = 1; j <= 4; j++) { lock (LockObj) { i = CommonCount; i++; Thread.Sleep(1); CommonCount = i; } Id = Thread.CurrentThread.ManagedThreadId; Console.WriteLine("Thread Id {0}, i = {1}", Id, i); } } static void Main(string[] args) { for (int i = 0; i < 4; ++i) { new Thread(new ThreadStart(ThreadFunc)).Start(); Thread.Sleep(1); } Thread.Sleep(40); Console.WriteLine("CommonCount = {0}", CommonCount); Console.ReadLine(); } } } Результат: Рис. 4.3 Синхронная работа потоков Вывод: Теперь при запуске приложения можно увидеть, что каждый поток получает возможность выполнять модификацию CommonCount без вмешательства других потоков. |