Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DiVM / OSISP / ОCиСП-Часть3 / Теория / Теория (ОСиСП).doc
Скачиваний:
29
Добавлен:
11.05.2015
Размер:
616.96 Кб
Скачать

Многозадачность

Параллельно выполняются подпрограммы и их синхронизация. Механизмы, заложенные для многозадачности в .Net, превосходят механизмы ОС Windows, UNIX.

Многозадачность в .Net, является многоуровневой. Существует понятие потока. Понятие процесса заменено – домен приложения.

Поток – наименьшая единица диспетчеризации в .Net. Потоки работают параллельно в соответствии с приоритетом. Потоки с более высоким приоритетом всегда вытесняют менее приоритетные.

В .Net существуют классы, которые являются классами-оболочками для объектов ОС-мы (среди них Thread).

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

Основная проблема многозадачных программ: все потоки в рамках одного домена приложения разделяют все глобальные данные, включая все динамические объекты в heap. Поэтому для доступа ко всем объектам ссылочных типов необходимо выполнять синхронизацию, гарантируя, что два потока не обратятся к свойствам одного объекта. Эта синхронизация – не только при записи, но и при чтении.

Требование синхронизации при чтении обусловлено тем, что программа может работать на многопроцессорном компьютере, для которого может возникнуть следующая проблема:

Есть два ЦП, у каждого из них есть свой КЭШ. Может оказаться следующее: в памяти есть объект, который читается двумя процессорами. Этот объект попадает в КЭШ ОП. Он же попадает в КЭШ процессора. При этом, если ЦП1 меняет объект, эти данные аппаратно переписываются в КЭШ-память ОП. Но у ЦП2 данные остаются в КЭШе. Поэтому без специальных механизмов синхронизации поток на ЦП2 читает старые данные. Т.о. необходима операция синхронизации КЭШа.

Аппаратные комплексы: ошибка, даже если просто чтение двух процессоров одного КЭШа. Поэтому синхронизация необходима всегда.

Для делегатов:

void delegate ControlChanged (Control c); // это делегат

class My

{

void ButtonChanged (Button b);

(b as Button)

}

есть класс:

class Control

{

ControlChanged; // в методе ButtonChanged этот делегат установить нельзя

// (т.к. другая сигнатура), надо преобразовать с использованием as

}

class Button: Control

{

}

А если по-другому:

void delegate ButtonChanged (Button b);

class My

{

void ControlChanged (Control c);

}

class Control

{

};

class Button: Control

{

ButtonChanged Changed; // этому методу можно присвоить ControlChanged

// без преобразований

}

Продолжаем потоки.

Многопоточность создается с помощью thread и с помощью объединения «спуллинга».

using System;

using System.Threading;

public class ThreadExample

{

public static void ThreadProc ( ) // 1

{

Console.WriteLine (“Tread Started”); // поток стартовал

Thread.Sleep (1000); // поток засыпает

Console.WriteLine (“Thread Finishing”); // поток завершается

} // теперь поток завершен

public static void Main ( )

{

Console.WriteLine (“ Starting Thread”);

Thread t=new Thread (new ThreadStart (threadProc)); // 2-создаем объект, в

// конструктор которого передается делегат (ThreadStart), который

// выполняется в отдельном потоке

t.Start ( ); // 3

Tread.Sleep(0); // 4

for (int i=0; i<1000; i++)

{

Console.WriteLine (“Main Thread doing some work”);

Thread.Sleep (100);

};

Console.WriteLine (“Waiting secondary thread”);

t.Join ( ); // 5-один поток (главный) ждет другой поток (ждет завершения

// вторичного)

Console.WriteLine (“Tread Finished”);

};

Процедура, выполняющаяся в потоке, должна быть объявлена как

1: public stasic void ThreadProc ( ) – без параметров (static - необязательно)

2: new ThreadStart (ThreadProc) – это создание не объекта, а делегата, куда в качестве параметра передается объект потока

3: t.Start ( ) - запуск потока. Но после выполнения этого метода поток не всегда физически возникает (в однопроцессорных машинах), а создается, когда завершится главный поток

4: если напишем Thread.Sleep(0), то главный поток прерывается, и управление передается дочернему (вторичному) потоку.

5: главный поток ожидает вторичный поток (поток t), а не наоборот.

Это использование потоков, которые (объект Thread) отображаются ОС-мой. Объект Thread используется, когда надо гарантированно выделить другой поток.

Второй пример:

using System;

using System.Threading;

public class ThreadExample

{

public static void ThreadProc (Object stateInfo )

{

Console.WriteLine (“Tread Started”);

Thread.Sleep (1000);

Console.WriteLine (“Thread Finishing”);

}

public static void Main ( )

{

Console.WriteLine (“ Starting Thread”);

ThreadPool.QueueUserWorkItem(new WaitCallback (ThreadProc)); // 1

for (int i=0; i<1000; i++)

{

Console.WriteLine (“Main Thread doing some work”);

Thread.Sleep (100);

}

}

}

Этот способ используется чаще. Для первого метода недостатки: если пришло 1000 запросов, то будет создано 1000 потоков. Поэтому все запросы клиентов будут работать медленно. Обычно используется 8 потоков на 1 процесс (один процессор) – это наиболее эффективно, и надо создавать поток, не когда пришел запрос, а когда используется некоторый пул потоков. Если работы слишком мало, то некоторые потоки отдыхают (ничего не делают), а если много задач – то потоки ставятся в очередь.