Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Медведев_С++_CLI_C#_Java_J#.doc
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
5 Мб
Скачать
☆

9.6.2.2. Связи между потоками в c#

Монитор (monitor) реализует механизм, обеспечивающий синхронизи-

рованный доступ к разделяемому объекту из критической секции, представ-

ленной фрагментом программы. При выполнении критической секции пото-

ком доступ к разделяемому объекту других потоков блокируется.

Класс Monitor содержит статические функции Enter(), TryEnter(),

Wait(), PuIs(), PulsAll() и Exit(). Поскольку эти функции статические, при

применении этого класса нет необходимости в создании объектов монитора.

Достаточно зафиксировать начало и конец критической секции, используя

функции Enter() и Exit() с указанием ссылки на разделяемый объект. Функ-

ции TryEnter(), Wait(), Puls(), PulsAll() управляют синхронизацией. Функция

TryEnter() фиксирует начало критической секции только в том случае, если

разделяемый объект не заблокирован, то есть не используется другим пото-

ком. Функция Wait() ожидает, когда разделяемый объект будет разблокиро-

ван иным потоком; после разблокировки критическая секция возобновит вы-

полнение. Функции Puls() и PulsAll() посылают сигнал одному или всем

ждущим потокам, информируя об изменении состояния блокированного

разделяемого объекта. Ожидаемые потоки выстраиваются в очередь готовых

к выполнению потоков. После разблокировки они синхронно разделят доступ

к объекту между собой.

Пример 9.6.2.2.1 показывает использование монитора вместо оператора

lock программы примера 9.6.1.1.

Пример 9.6.2.2.1. Monitor и потоки.

///////////////

/ / C #

uslng System; using System.Threading;

class Obj // Класс разделяемого объекта

{

private lnt count= 0;

public int Count

<

set {count= value;}

get {return count;> >

>

class User // Класс объектов с потоками

{

private Obj obj;

int num;

Thread thr;

public User (Obj obj, int num)

{

this.obj= obj;

this.num= num;

thr= new Thread (new ThreadStart (this.ThrFunc));

thr.Start ();

>

private void ThrFunc ( )

{

//Monitor.Enter (obj); // 3 Начать критическую секцию

while (obj.Count < 5)

{

Monitor.Enter (obj); // 2 Начать критическую секцию

obj.Count= obj.Count +1;

Thread.Sleep (1);

Console.WriteLine("User " + num + " count= "

+ obj.Count);

Monitor.Exit (obj); // 2 Завершить критическую секцию

}

Console.WriteLine (Thread of User " + num +

" flnlshed");

// Monitor.Exit (obj); // 3 Завершить критическую секцию >

public void Finish ( ) {thr.Join ();>

>

class LockTest

{

static void Main ( )

{

Obj obj= new Obj ( );

User usl= new User (obj, 1);

User us2= new User (obj, 2);

Console.WriteLine ("OKl");

usl.Finish ( );

us2.Finish ( );

Console.WriteLine("OK2");

>

/>*

Resultl : Monitor не применён

(строки 2 и 3 закомментированы)

OKl

Userl count= 1

User2 count= 1

Userl count= 3

User2 count= 3

Userl count= 5

Thread of Userl finished

User2 count= 5

Thread of User2 flnished

OK2

Result2: Monitor.Enter (obj);w Monitor.Exit (obj);

охватывает оператор while внутри

(строки 2 не закомментированы, а строки 3 закомментированы)

OKl

Userl count= 1

User2 count= 2

Userl count= 3

User2 count= 4

Userl count= 5

Thread of Userl finished

User2 count= 6

Thread of User2 finished

OK2

Result3: Monitor.Enter (obj);n Monitor.Exit (obj);

охватывает оператор while снаружи

(строки 2 закомментированы, а строки 3 не закомментированы)

OKl

Userl count= 1

Userl count= 2

Userl count= 3

Userl count= 4

Userl count= 5

Thread of Userl finished

Thread of User2 finished

OK2

*/

В примере 9,6.2.2.1, как и в примере 9.6.1.1, класс Obj описывает тип разде-

ляемого объекта. Класс User описывает тип объектов, каждый из которых

включает поток, потоковая функция которого содержит критическую сек-

цию. Критическую секцию начинает функция Enter() и завершает функция

Exit(). Эти функции привязывают критическую секцию к разделяемому объ-

екту, ссылка obj на который передаётся конструктором при создании объек-

та с потоком. При каждом выполнении критической секции разделяемый

объект блокируется монитором, и критическая секция увеличивает значение

счётчика разделяемого объекта, осуществляет задержку и выдачу на консоль.

При этом разделяемый объект не доступен другим потокам (и, разумеется,

содержащимся в них критическим секциям).

Пример 9.6.2.2.2 показывает, что функции Wait() и Pulse() позволяют,

как и функции wait() и notify() языка Java (см. пример 9.6.2.1.1), приостано-

вить и возобновить выполнение нотока без применений запрещённых функ-

ций Suspend() и Resume() класса Thread.

Пример 9.6.2.2.2. Приостановка и возобновление потока в C#

///////////////

/ / C #

using System; using System.Threading;

public User ( )

{

thls.n= 0;

moving= true;

// Создать и стартовать поток

thr= newThread (newThreadStart(this.ThrFunc));

thr.Start ();

}

public vold SuspendUser ( ) // Приостановить поток

class User

{

int n;

// Класс объектов с потоками

// Порядковый номер цикла потока

// Ссылка на поток

// Признак выполнения потока

Thread thr;

bool moving;

{

moving= false;

>

public void ResumeUser ( )

{

lock (this)

{

// Создать синхронизируемый блок

// Возобновить поток

moving= true;

Monitor.Pulse (this); // Разблокировать поток

>

>

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

private void ThrFunc ()

{

while (n < 10)

{

Thread.Sleep (10);

lock (this) // Создать синхронизируемый блок