Вы находитесь на странице: 1из 11

Лабораторная работа N1.

Разработка многопоточного приложения


в Windows
Содержание работы: Разделение вычислений между нитями
(потоками) Windows.
Количество потоков является параметром программы. Количество
исходных данных не кратно в общем случае количеству потоков.
Выполнить вычисления в однопоточном и многопоточном режиме и
сравнить времена выполнения.
Теоретические положения, необходимые для выполнения работы.
Что такое нить?
Каждый процесс может создавать несколько нитей.
Каждая нить представляет собой независимо выполняющийся поток
управления со своим счетчиком команд, регистровым контекстом и стеком.
Потоки предоставляют возможность проведения псевдопараллельных
вычислений. Различные потоки имеют различный порядок выполнения, но
при этом пользуются общей памятью. Действия потока задаются при его
создании указанием его функции, созданный поток начинает выполнять
команды этой функции и завершается, когда происходит возврат из функции.

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


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

Параллельное программирование - это техника программирования, которая


использует преимущества многоядерных или многопроцессорных
компьютеров и является подмножеством более широкого понятия
многопоточности (multithreading).

Многоядерные вычисления

Использование параллельного программирования становится наиболее


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

1
Потоки в Windows

C# поддерживает параллельное выполнение кода через многопоточность. Программа на


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

Все примеры предполагают, что импортируются следующие


пространства имен (если этот момент специально не оговаривается):
using System;
using System.Threading;
1. Для того, чтобы использовать многопоточность, используем директиву
System.Threading:

using System.Threading;
2. Теперь, создадим три различных метода, которые будут выполняться в
различных потоках:

static void FirstThread()


{
for (int i=0;i<10;i++)
{
Console.WriteLine("Первый поток говорит: Hello!");
}
}
static void SecondThread()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Второй поток говорит: World!");
}
}
static void ThirdThread()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Третий поток говорит: Hello World!");
}
}
3. В методе Main создаем потоки:

Thread thread1 = new Thread(new ThreadStart(FirstThread))


Thread thread2 = new Thread(new ThreadStart(SecondThread))
Thread thread3 = new Thread(new ThreadStart(ThirdThread))
2
В нашем случае поток:

o thread1 - вызывает метод FirstThread


o thread2 - вызывает метод SecondThread
o thread3 - вызывает метод ThirdThread
4. Запускаем потоки, с помощью метода Start():

thread1.Start()
thread2.Start()
thread3.Start()
5. Добавим на вывод в главном потоке (метод Main), следующие строчки:

Console.WriteLine("Главный поток молчит")


Console.WriteLine("Завершение главного потока")
Console.ReadLine()
6. Запустим приложение. Результат будет следующим:

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


по времени.
2. Для того, чтобы задать время блокировки, на выполнение потока,
используем метод Sleep(). Для главного потока установим время
блокировки 1000мс:

Thread.Sleep(1000)
Console.WriteLine("Главный поток молчит")
Console.WriteLine("Завершение главного потока")
Console.ReadLine()
3
3. Аналогично, установим время блокировки, для дочерних потоков 20мс,
100мс, 90мс:

static void FirstThread()


{
for (int i=0;i<10;i++)
{
Thread.Sleep(20);
Console.WriteLine("Первый поток говорит: Hello!");
}
Console.WriteLine("Завершение первого потока");
}
static void SecondThread()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
Console.WriteLine("Второй поток говорит: World!");
}
Console.WriteLine("Завершение второго потока");
}
static void ThirdThread()
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(90);
Console.WriteLine("Третий поток говорит: Hello World!");
}
Console.WriteLine("Завершение третьего потока");
}
4. Запустим программу. Результат будет следующим:

4
Как видно из результата выполнения программы: первый поток завершится
первым, т.к время блокировки составляет 20мс. Второй и третий поток будут
выполняться почти одновременно, т.к время блокировки составляет 90мс и
100мс. Второй поток и главный поток завершатся почти одновременно т.к
общее время блокировки второго и главного потока составляет 1000мс.
Метод Join блокирует вызывающий поток до тех пор, пока указанный поток
(тот, в котором вызван Join()) не завершен
thread1.Start();
thread2.Start();
thread3.Start();
thread1.Join();
thread2.Join();
thread3.Join();
Для передачи функции потока параметров записывается так называемое
лямбда-выражение. Например:
static void Print(string message,out string mes)
{mes="XaXa";
Console.WriteLine(message);
}
string rez = "XoXo";
Thread t = new Thread(() => Print("Hello from t!",out rez));
t.Start(); t.Join();
5
Console.WriteLine(rez);
Программа создается в Visual Studio 2008 C# как консольное приложение.
Для этого при создании проекта выбирается пункт меню File, New,Project.
Появляется окно:

Выбирается
этот вариант

Если программа принимает параметры, то они задаются в окне Project


Properties.

6
Для определения времени расчетов необходимо добавить директиву
using System.Diagnostics;
Далее необходимо создать экземпляр типа Stopwatch:
Stopwatch sWatch = new Stopwatch();
В необходимый момент времени (непосредственно перед началом
выполнения измеряемых операций) запускаем отсчет системного времени:
sWatch.Start(); //любой набор операций (работа с базой данных)
В конце выполнения измеряемых операций останавливаем счет:
sWatch.Stop();
Теперь, можем вывести значение затраченного времени в миллисекундах:
Console.WriteLine (sw.ElapsedMilliseconds.ToString());
Если время на порядки больше миллисекунд, то удобнее пользоваться типом
TimeSpan:
TimeSpan tSpan;
tSpan = sWatch.Elapsed;
Console.WriteLine(ts.ToString());
Данные для расчетов генерируются датчиком псевдослучайных чисел в виде
массива с помощью фрагмента:
Random rnd1 = new Random();
for (i = 0; i < 100; i++)
a[i] = rnd1.Next(10, 20);

7
Пример программы
Дана последовательность натуральных чисел a0, …, a99. Создать
поточное приложение для поиска суммы квадратов ∑ai2
В качестве примера рассмотрим случай, когда в массиве хранятся номера
элементов. Основной поток создает нужное число потоков, число которых
задается параметром, каждому из которых передается параметр – номер
процесса (или номер части массива, обрабатываемой потоком). Функция
потока возвращает частичную сумму. Основной поток ожидает завершения
всех потоков и находит общую сумму.
Текст программы:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace MultiThread
{
class Program
{static int []a=new int [1000];
static int n;
static void ThreadFunc(int param, out int sum) //Функция потока
{
int i,nt,beg,h,end;
sum=0;
nt=param;
h=1000/n;
beg = h*nt;end=beg+h;
if (nt==n-1)
end=1000;
Console.WriteLine("Поток {0} начало {1} конец {2}",nt,beg,end);
for(i=beg;i<end;i++) sum += a[i]*a[i];
}

static void Main(string[] args)


{n=Convert.ToInt32(args[0]);
Stopwatch sWatch = new Stopwatch();
short start1, finish1,start2,finish2;
int i;
Thread [] thread =new Thread[n];
int [] s1=new int[n];
int rez=0,s = 0;

8
int[] x = new int[n];
for (i=0;i<100;i++)
a[i] = i;
sWatch.Start();
//создание n дочерних потоков
for (i=0;i<n;i++)
{x[i]= i;thread[i] = new Thread(()=>ThreadFunc(x[i],out s1[i]));
thread[i].Start(); thread[i].Join();
}
for(i=0;i<n;i++) rez+=s1[i];
sWatch.Stop();
Console.WriteLine (sWatch.ElapsedMilliseconds.ToString());
Console.WriteLine("Сумма квадратов с {0} потоками = {1}",n,rez);
sWatch.Start();
for (i = 0; i < 1000; i++) s += a[i]*a[i];
sWatch.Stop();
Console.WriteLine(sWatch.ElapsedMilliseconds.ToString());
Console.WriteLine("Сумма квадратов без потоков = {0}", s);
Console.ReadLine();
}
}
}
Результат работы программы:

Индивидуальные задания
1. Даны последовательности чисел А = {а0…аn–1} и С = {с0…сn–1}.
Создать многопоточное приложение, определяющее, совпадают ли
поэлементно строки А и С.
2. Дана последовательность чисел С = {с0…сn–1}. Дан набор из N пар
кодирующих чисел (ai,bi), т.е. все ai заменяются на bi. Создать
9
многопоточное приложение, кодирующее последовательность С следующим
образом: массив разделяется на подмассивы и каждый поток осуществляет
кодирование своего подмассива.
3. Дана последовательность чисел С = {с0…сn–1} и число b. Создать
многопоточное приложение для определения количество вхождений числа b
в массив C.
4. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для поиска произведения чисел a0*а1*…*an–1.
5. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для поиска максимального ai.
6. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для поиска минимального ai.
7. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для поиска всех ai, являющихся простыми
числами.
8. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для поиска всех ai, являющихся квадратами,
любого натурального числа.
9. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для вычисления выражения a0-а1+a2-а3+a4-а5+...
10. Дана последовательность натуральных чисел {a0…an–1}. Создать
многопоточное приложение для поиска суммы ∑ai, где ai – четные числа.
11. Изготовление знаменитого самурайского меча – катаны происходит
в три этапа. Сначала младший ученик мастера выковывает заготовку
будущего меча. Затем старший ученик мастера закаливает меч в трех водах –
кипящей, студеной и теплой. И в конце мастер собственноручно
изготавливает рукоять меча и наносит узоры. Требуется создать
многопоточное приложение, в котором мастер и его ученики представлены
разными потоками. Изготовление меча представить в виде разных
арифметических операций над глобальной переменной.
12. Изготовление знаменитого самурайского меча – катаны происходит
в три этапа. Сначала младший ученик мастера выковывает заготовку
будущего меча. Затем старший ученик мастера закаливает меч в трех водах –
кипящей, студеной и теплой. И в конце мастер собственноручно
изготавливает рукоять меча и наносит узоры. Требуется создать
многопоточное приложение, в котором мастер и его ученики представлены
одинаковыми потоками (обработка производится в цикле). Изготовление
меча представить в виде разных арифметических операций над глобальной
переменной.
13. Даны результаты сдачи экзамена по N студенческим группам.
Требуется создать многопоточное приложение, вычисляющее средний балл.
Потоки должны осуществлять вычисления параллельно по группам.
10
14. Охранное агентство разработало новую систему управления
электронными замками. Для открытия двери клиент обязан произнести
произвольную фразу из 25 слов. В этой фразе должно встречаться заранее
оговоренное слово, причем только один раз. Требуется создать
многопоточное приложение, управляющее замком. Потоки должны
осуществлять сравнение параллельно по словам.
15. Дан список студентов по группам. Требуется создать
многопоточное приложение для определения количества студентов с
фамилией Иванов. Потоки должны осуществлять поиск совпадений по
группам параллельно.
16. Среди студентов университета проведен опрос с целью определения
процента студентов, знающих точную формулировку правила Буравчика. В
результате собраны данные о количестве знатоков на каждом факультете по
группам. Известно, что всего обучается 10000 студентов. Требуется создать
многопоточное приложение для определения процента знающих правило
Буравчика студентов. Потоки должны осуществлять поиск количества
знатоков по факультету. Искомый процент определяет главный поток.
17. Даны результаты сдачи экзамена по группам. Требуется создать
многопоточное приложение, вычисляющее количество двоечников и
отличников. Потоки должны осуществлять вычисления параллельно по
группам.
18. Руководство заготовительной компании «Рога и Копыта» проводит
соревнование по заготовке рогов среди своих региональных отделений. Все
данные по результатам заготовки рогов (заготовитель, его результат)
хранятся в общей базе данных по отделениям. Требуется создать
многопоточное приложение для поиска лучшего заготовителя. Потоки
должны осуществлять поиск победителя параллельно по отделениям.
Главный поток определит победителя.

11

Вам также может понравиться