- •2. Основные понятия объектно-ориентированного программирования 7
- •3. Управляемый и неуправляемый код и данные 17
- •3.3 Управляемый и неуправляемый код и данные 17
- •5. Классы 38
- •6. Наследование классов и интерфейсы 49
- •7. Программа ввода/вывода информации 62
- •8. Управляемые данные и их использование 76
- •Предисловие
- •2.1 Объекты
- •2.Основные понятия объектно-ориентированного программирования
- •2.2Классы
- •Пример 2.2.2. Создание и использование объектов.
- •2.3Объекты, классы и uml
- •2.4Основные свойства объектно-ориентированного программирования
- •Пример 2.4.1. Класс cColBall, наследуемый класс cBall.
- •Пример 2.4.2. Использование функций объектов.
- •2.5Библиотеки классов
- •3.Управляемый и неуправляемый код и данные
- •3.1Виртуальная машина языка Java
- •3.2Общеязыковая среда выполнения clr платформы .Net
- •3.3Управляемый и неуправляемый код и данные
- •3.4Сборщик мусора
- •3.5Ссылочные типы и типы-значения
- •3.6Метаданные
- •3.7Библиотеки, пакеты и пространства имён
- •4.1О типах данных
- •4.2Консольный ввод и вывод
- •Void main (void)
- •Import java.Io.*;
- •Int X; // Целочисленная переменная X
- •4.3Объявление переменных
- •4.4Операторы динамического распределения памяти new и delete
- •Int X; // Выделить память в стеке
- •Пример 4.4.2. Использование оператора new в языках Java и c#.
- •Import java.Io.*;
- •Int X; // Выделить память в стеке для переменной
- •Int X; // Выделить память в стеке для переменной
- •4.5 Массивы
- •Пример 4.5.2. Описание одномерных массивов на изыках Java и c#.
- •Пример 4.5.4. Создание массивов объектов на языке Java.
- •Import java.Io.*;
- •4.6Объявления структур и перечислений
- •4.7Ссылки
- •Пример 4.7.1. Использование ссылочной переменной.
- •Void main()
- •4.8Перегрузка функций
- •Пример 4.8.1. Перегруженные функции swap (int &, int &) и swap (bool &,bool &).
- •Void swap (int &a, int &b) // Целочисленные параметры
- •Void swap (bool &a, bool &b) // Булевские параметры
- •4.9Объявление функций и передача аргументов по умолчанию
- •Void swap (int &, int &);
- •Void swap (char 8t, char &);
- •Пример 4.9.1. Задание значений параметров функции по умолчанию.
- •Void main ( )
- •5.Классы
- •5.1Определение класса
- •Пример 5.1.1. Описание класса и создание его объектов.
- •Int X; // Закрытая переменная X
- •Void Show ( ) // Открытая функция
- •Int X; // Закрытая (по умолчанию) переменная X
- •Void Show ( ) // Открытая функция
- •Пример 5.2.1. Описание функций вне класса.
- •Int X; //Закрытая переменная х
- •Void Set(int m,char n); // 0бъявление функции Set
- •Void Show (); // Объявление функции Show()
- •5.3Некоторые замечания о классах
- •Пример 5.3.1. Области видимости.
- •Int GetK() {return k;} // Функция GetK() видна в файле, классе а и в
- •Int n; // Переменная n закрыта и видна только в классе а
- •Int GetM () {return n;} // Функция GetM() открыта и видна
- •5.4Объекты в объектах
- •Пример 5.4.1. Объект содержит объект другого класса.
- •Void Show ()
- •Void Show ()
- •5.5Специальный вид функций класса - конструкторы и деструкторы
- •Пример 5.5.1. Перегруженные конструкторы.
- •Int GetX() {return X;} // Возвратить значение закрытой переменной
- •Void ShowX () // Вывести значение переменной
- •5.6Статические функции класса
- •Пример 5.6.1. Статические функции.
- •Void f() {Console::WriteLine("f()");} // Обычная функция
- •Int main() // Главная статическая функция Main()
- •6.Наследование классов и интерфейсы
- •6.1Об интерфейсах
- •Пример 6.2.1. Программа, использующая порождение public.
- •Void Show ()
- •Void Show()
- •Int main() // Главная статическая функция
- •6.4Использование конструктора базового класса
- •Java и j#
- •Java и j#
- •Пример 6.4.1. Выполнение конструкторов.
- •Int X; // Закрытая переменная X
- •Int Get() {return X;} // Получить значение X
- •Int main() // Главная статическая функция main()
- •6.5Сокрытые переменные, функции и их использование
- •Пример 6.5.1. Сокрытые переменные и функции.
- •6.6Интерфейсы
- •Interface class имя-интерф [ : public имя-базов-интерф
- •Interface имя-интерф [ : имя-базов-интерф [, имя-базов-интерф ] ... ]
- •Interface имя-интерф [ extends имя-базов-интерф
- •Interface Ipe // Интерфейс, объявляющий свойство p и функцию Hallo
- •Int p {set; get;} //Объявить свойство
- •Void Hallo(); // Объявить функцию
- •6.6.1Определение интерфейса
- •6.6.2Базовые интерфейсы
- •6.7 Упаковка и распаковка типов данных
- •Int main() // Главная статическая функция main()
- •7.Программа ввода/вывода информации
- •7.1Постановка задачи
- •Диаграмма вариантов использования
- •7.2 Диаграмма классов
- •7.3Диаграмма последовательности
- •7.4Диаграмма видов деятельности
- •Пример 7.5.1. Реализация класса cComputer.
- •Пример 7.5.2. Реализация класса cShop.
- •Пример 7.5.3. Реализация класса cData.
- •Void main()
- •Пример 7.5.4. Реализация Inf-приложения.
- •Void main()
- •7.6Реализация Inf-приложения иа языке c# Пример 7.6.1. Реализация Inf-приложения иа языке c#.
- •Int cost; // Стоимость компьютера
- •Int year; // Год изготовления
- •Inf.Enter();
- •Inf.Enter();
- •Inf.Show();
- •8.Управляемые данные и их использование
- •Void set(тип value)
- •Пример 8.1.2. Свойства в Java.
- •Import java.Io.*;
- •Пример 8.2.1. Создание и использование делегата.
- •Void main() // Главная функция программы
- •Пример 8.2.2. Использование делегата как параметра функции.
- •Void r(void) {Console::WriteLine ("r");}
- •Void main () // Главная функция программы
- •Void имя-функции ( void );
- •Пример 8.3.1. Событие и делегат.
- •Void main ()
- •Vold имя-функции-активизации()
- •Пример 8.3.2. Использование события.
- •Void GenerateEv() // Функция-генератор события
- •Void main()
- •Void GenerateEv (String л str) // Функция- генератор события
- •Void main ( )
- •06BeKTfirst клaccaUseEvпoлyчилcoбытиe one
- •Interface iEv
- •IE,HandlerEv (); // Выполнить обработчик
- •Void GenerateEv ( ) // Сгенерировать событие
- •Void main (void)
- •V{ oid FireConnectEvent (object sender, SourceEventArgs e)
- •Void FireConnectEvent (object sender, EventArgs args)
- •8.4. Уведомления и события в Java
- •8.4.1. Уведомления в Java
- •Void notifyObservers () - уведомить всех обозревателей данного наблюдаемого
- •Void notifyObservers (Object obj) - уведомить всех обозревателей данного на-
- •Void update(Observable observable. Object obj) - эта функция данного объекта
- •Import java.Util.*;
- •II Два наблюдателя и один наблюдаемый объект
- •Importjava.Util.*;
- •Importjava.Utll,*;
- •Importjava.Util.*;
- •Int num; // Номер уведомляющего объекта
- •8.4.2. События в Java
- •Import java.Utii.*;
- •Void DatePerformed (DataDate dd); // Обработчик
- •Int n; // Номер объекта-приёмника
- •Int num; // Номер объекта приёмника
- •Import cJHappenListerner.*;
- •Importjava.Uti).*;
- •Void performedHappen (HappenData hD);
- •Import cJHappenListerner.*; | | Импортировать библиотеку
- •9. Потоки и синхронизация их выполнения
- •9.1. Процессы
- •9.3. Потоки в Java
- •Int num; // Номер потокового объекта
- •2. Поскольку объявленному в классе cThread потоковому объекту thr типа
- •9.4. Потоковый объект, выдающий событие
- •If (lllfe) // Если потоковый объект не функционирует,
- •ImportJava,util.*;
- •If (!life) // Если потоковый объект не функционирует,
- •9.5. Поток получил событие из объекта
- •If (!life)
- •If (received)
- •Importjava.Utll.*;
- •If (lllfe)
- •If (received)
- •9.6. Синхронизация выполнения потоков
- •9.6.1. Операторы lock и synchronized
- •Int num; // Номер объекта
- •9.6.2. Связи между потоками
- •9.6.2.1. Связи меяеду потоками в Java
- •If(waiting)
- •9.6.2.2. Связи между потоками в c#
- •If (I moving)
- •9.6.2.1.1 Наязыке Java, отличаясьтолько применением функций монитора
- •10. Библиотека .Net Framework и библиотеки
- •10.1. Приложение
- •10.2. Классы, объекты и элементы приложения
- •Visual Studio .Net как библиотеки .Net Framework, так и пакетов языка Java
- •10.3. Простейшие приложения
- •Import java.Awt.*;
- •Void main ( )
- •10.3.1.1. Оказывается, класс Form сам наследует множество других классов,
- •10.4. Сообщения Windows, события и делегаты
- •X0.4.1. Обработка событий мыши на языке c#
- •Void OurMouseDown (object sender, MouseEventArgs args);
- •Vold maln ()
- •10.4.3. Обработка событий мыши на языке Java с использо-
- •10.4.4. Связь события с несколькими объектами на языке c#
- •10.5. Ещё раз о событиях и уведомлении в языке Java
- •10.5.1. Обработка событий элементов интерфейса пользовате-
- •ItemListener, KeyListener, MouseListener, MouseMotionListener, TextListener
- •10.5.2. Обработка событий мыши на языке Java, используя
- •Importjava.Awt.Event.*;
- •Importjava.Awt.*;
- •Import java.Awt.Event.*;
- •Importjava.Awt.*;
- •Import java.Awt.Event.*;
- •10.5.3. Обработка событий мыши на языке Java, используя классы адап-
- •Importjava.Awt.*;
- •Importjava.Awt.Event.*;
- •Importjava.Awt.*;
- •Importjava.Awt.Event.*;
- •10.5.4. Обработка событий мыши на языке Java, используя внутренние
- •Import java.Awt.*;
- •Import java.Awt.Event.*;
- •Importjava.Awt.*;
- •Import java.Awt.Event.*;
- •10.5.5. Обработка события закрытия окна
- •Import java.Awt.*;
- •Import java.Awt.Event.*;
- •10.6. Графика
- •10.6.1. Графические объекты
- •15, 15, 60, 70); // Нарисовать эллипс
- •Vold maln ()
- •10.7. Событие Paint и его обработчик
- •Int len; // Текущая длина массива points
- •Void OurMouseDown (object sender, MouseEventArgs arg)
- •Invalidate ( ); // Перерисовать
- •Int len; // Текущая длина массива points
- •Import java.Awt.Event.*;
- •10.8. Управляющие элементы
- •1 «Button j 1
- •Import java.Awt,event.*;
- •Int n; // Индекс цвета
- •10.8.4,10.8.5 И 10.8.6, а также программа, поэтапно разрабатываемая в разде-
- •Invalidate ();
- •Importjava.Awt.*;
- •Import java.Awt.Event.*;
- •Importjava.Util.*;
- •10.9. Дочерние окна
- •Int n; // Индекс массива colors
- •IiTipOrt jav'a.Avvt. •)
- •Import java.Awt.Event.*;
- •Int n; // Индекс цвета
- •Virtual void OnPaint (PaintEventArgs л arg) override // Перерисовать область
- •10.10.3, В котором вызываются две функции.
- •Importjava.Awt.*;
- •Importjava.Awt.Event.*;
- •It); // Подписать обработчик
- •Void main ( )
- •11.1. Программа с точки зрения пользователя
- •11.2. Объектное представление программы
- •11.3. События, потоки и их синхронизация
- •11.4. Поэтапная разработка программы
- •11.4.1. Первый этап. Разработка класса Warehouse
- •4Cxrt()
- •Int partLoad; // Выгружаемая или загружаемая порция
- •If(full) return false; // Полный грузовик не загружать
- •Invalidate ();
- •Importjava.Awt.*;
- •Importjava,utll.*;
- •Void notifyObs (WarehouseEventArgs arg)
- •Int partLoad; // Получаемая или помещаемая порция груза
- •If (full) return false;
- •If(full) return false; // Полный грузовик не загружать
- •Void Change ( )
- •Invalidate ();
- •Importjava.Awt.*;
- •Importjava.Util.*;
- •Import cjWarehouse.*
- •11.4.2. Второй этап. Разработка классов ContrlRegion и Lorry
- •11.4.2.1, А сам класс представлен в примере 11.4.2.1. Класс ContrlRegion язы-
- •Importjava.Awt.Event.*;
- •Void Work ( ) // Выполнить работу
- •Int number;
- •Int number;
- •Int timePeriod;
- •Int y; // Координата y пути грузовика
- •Invalidate ();
- •11.4.3. Третий этап. Разработка приложения csLorryAndWarehouse
- •4IorryAndWa rho uses()
- •4Main()
- •Int y; // Координата y пути грузовика
- •Invalidate ( );
- •If(lorry.GetFull())
- •If(lorry.GetLeftRight()) g.SetColor(Color.Red);
- •Int numLorry; // Номер грузовика
- •Void But_Run (Object Ло, EventArgs ле)
- •Void main ( )
- •11.4.4. Четвертый этап. Удаление ресурса
- •Int number;
- •If(!lorry.Running)lorry.Run ( );
- •12. Зачетные задачи
- •12.1. Задание 1
- •Importjava.Awt.*;
- •Import Java.Awt.Event.*;
- •Importjava.Util.*;
- •12.2. Задание 2
- •Importjava.Awt.*;
- •Importjava.Awt.Event,*;
- •Importjava.Util.*;
- •Invalidate ( );
- •12.3. Задание 3
- •Importjava.Awt.*;
- •Import java.Awt.Event.*;
- •Importjava.Util.*;
- •If(bool) Start ();
- •If(lrunnlng)
- •Void BallFunc ()
- •Void ThrFunc ( )
- •Vold OnButAdd (object obj, EventArgs arg)
- •Void HandlerEv ( )
- •Invalidate ( );
- •12.4. Задание 4
- •If(reg.R.Contains(p) && !inRect)
- •If(!reg.R,Contains(p) && lnRect)
- •Void OnButAdd (object obj, EventArgs arg)
- •Void HandlerEv ( )
- •Invalidate ();
- •Importjava.Awt.*;
- •Importjava.Awt.Event.*;
- •Importjava.Utll.*;
- •Int w, int h, Color c, Wind wind)
- •If(reg.R.Contains(p) && !lnRect)
- •If(!reg.R.Contains(p) && inRect)
- •If(d.GetDel())
- •13. Ещё о важном в объектно-ориентирован-
- •13.1. Виртуальные функции
- •13.1.1. Преобразование типов
- •Void f ( ) {cout « "ca:: f" « endl;}
- •Void main ( )
- •Void f ()
- •Void main ( )
- •Vold f ( )
- •Vold Do (ca* pCa)
- •Void main ( )
- •13.1.2, Виртуальные функции
- •Virtual void f ( ) {Console::WriteLine ("a:: f");}
- •Void f ( ) {Console::WriteLine ("b:: f");}
- •Void f ( ) {Console::WrlteLlne ("c:: f");}
- •Vold f ( ) {Console::WrlteLlne("b:: f");}
- •Vold Do (a* pA)
- •Void main ()
- •13.1.3. Виртуальные функции, используемые в книге
- •13.2. Абстрактные классы и функции
- •13.2.1. Абстрактные функции
- •13.2.2. Абстрактные классы
- •Void f ( ) {Console::WriteLine ("b:: f");}
- •Vold f ( ) {Console::WriteLine ("d:: f");}
- •Vold main ( )
- •13.2. Нововведения в языке c#
- •13.2.1.Делегаты и события
- •Iorry.Run ( );
- •13.3.2. Статические классы
- •Int partLoad; // Выгружаемая или загружаемая порция
- •If(!full)
- •Invalidate ( );
- •Int number;
- •Int y; // Координата y пути грузовика
- •Iorry.Stop ();
- •If(llorry.Running)lorry.Run ( );
- •Invalidate ( );
- •1) Создать новый проект:
- •Value 28, 30
- •Value type 34
- •Visual Studio .Net и Edipse.
- •420111, Казань, Дзержинского, 3. Тел.: 292-24-76.
9. Потоки и синхронизация их выполнения
9.1. Процессы
Процесс process) - это программа (EXE файл), представленная в опе-
рационной системе как задача {task) и управляемая супервизором задач. Для
выполнения операционная система выделяет процессу необходимые ресурсы
и, в частности, область памяти, называемую адресным пространством про-
цесса. По мере надобности процесс может загружать в своё адресное про-
странство динамически компонуемые библиотеки (DLL — Dynamic Link Library)
или выделять в нём память для своих объектов или данных, которые
при необходимости могут быть удалены или заменены новыми.
Процесс может создать другие процессы, используя для управления
ими необходимые ЛР/-функции (API - Application Programming Interface).
Будучи созданными, процессы становятся независимыми и выполняются
параллельно с другими процессами.
Обычно каждый процесс в операционной системе представлен своим
прикладным окном (application window). Наличие окна с интерфейсными
элементами позволяет не только управлять программой, но и завершить про-
цесс, нажав на кнопку закрытия в его прикладном окне. Выполнение процес-
са состоит в выполнении составляющих его потоков.
Для обеспечения безопасности программного кода .NET технология в
рамках одного процесса создаёт один (по умолчанию) или произвольное ко-
личество (по желанию программиста) так называемых доменов, в которых
выполняется управляемый код.
9.2. Потоки в C# и C++/CLI
Под потоком (thread) понимают выполняющийся программный код.
Выполнение процесса начинается с выполнения основного потока
primary thread), представленного главной функцией main() или Main(). Ос-
новной поток обычно реализует диалог с пользователем. Основной поток
инициирует, выполняет и завершает работу процесса.
Если основной поток создаёт окно, то его называют основным оконным
потоком. Обычно с окном связан цикл обработки сообщений операционной
системы.
Основной поток может создать и запустить так называемые рабочие
потоки (work threads), которые будут выполняться параллельно с основным
и другими потоками.
В отличие от процесса потокам не предоставляются ресурсы. Поэтому
каждый из запущенных потоков будет выполняться в одном и том же адрес-
ном пространстве, выделенном процессу, к которому эти потоки принадле-
жат. Потоки создаются, запускаются, приостанавливаются и возобновляются
путём вызова API-функций. После завершения процесса все принадлежав-
шие ему потоки уничтожаются.
Если выполнение основного потока сводится к выполнению главной
функции Main() или main() приложения, то выполнение каждого рабочего по-
тока связано с выполнением так называемой его потоковой функции. Завер-
шение выполнения потоковой функции завершает выполнение потока. В при-
мерах программ данной книги потоковая функция содержит цикл while, оп-
ределяющий время жизни потока. В теле оператора while вызывается функ-
ция Sleep() или sleep(), приостанавливающая выполнение данного потока на
заданный промежуток времени, в течение которого выполняются другие по-
токи (ведь, процессор, выполняющий потоки, один!). Перед запуском неко-
торого потока необходимо установить значение булевского выражения его
оператора while, равным true. Для завершения выполнения потока достаточ-
но сделать это выражение, равным false.
В языках Java и C# потоки создаются и применяются по разному. В ка-
ждом из этих языков рабочий поток является объектом класса Thread. Но ес-
ли в языке C#, использующем библиотеку .NET Framework, объект потока
можно создать везде, где он, действительно, нужен, и можно создать просто
в одном потоке несколько "дочерних" потоков, то в языке Java, в виду ис-
ключительности потока, наложены ограничения, которые приходится учиты-
вать. В языке Java имя потоковой функции для всех рабочих потоков одно и
то же - run(). В классе может быть создан поток, если класс порождён (extends)
из потокового класса Thread, либо наследует (implements) интерфейс
Runnable. Потоки языка Java будут рассмотрены в разделе 9.3.
Для реализации потоков на языке C# библиотека .NET Framework со-
держит более 20 классов и структур, среди которых следует, прежде всего,
выделить потоковый класс Thread и делегат ThreadStart потока.
Класс Thread используется для создания и управления потоками, а тип
ThreadStart - для создания объекта делегата потока, инкапсулирующего по-
токовую функцию.
Среди множества функций и свойств класса Thread мы выделим функ-
цию Start() запуска потока (запуска потоковой функции потока), функцию
Suspend() приостановки потока, функцию Resume() возобновления выполне-
ния потока и функцию Join() ожидания завершения указанного потока.
При создании экземпляра потока конструктору класса Thread передаёт-
ся в качестве аргумента объект делегата, инкапсулирующий потоковую
функцию. При этом возможны два варианта перегруженного конструктора
делегата: 1) указывается статическая потоковая функция некоторого класса
или 2) указывается потоковая функция конкретного объекта определённого
класса.
При объектно-ориентированном программировании целесообразно свя-
зать с потоком ряд данных некоторого класса, то есть, по сути дела, привя-
зать поток к конкретному классу, данные которого будут использоваться и
обрабатываться потоком. Будем такой класс называть классом потокового
объекта. Создав из класса потокового объекта множество потоковых объек-
тов и запустив их потоковые функции, мы получим параллельно функцио-
нирующие потоковые объекты. Они могут представлять, например, сово-
купность самолётов или людей. Каждая из этих совокупностей характеризу-
ется набором своих данных, определяющих состояние её объектов, и набо-
ром функций, определяющих поведение объектов.
Целесообразно включить в потоковый объект булевскую переменную
(например, bool life), которая будет определять жизненный цикл потока и
которой перед запуском этого потока присваивается истинное значение
(true). Жизненный цикл реализуется в потоковой функции с помощью опера-
тора while, условие которого содержит эту переменную. Поток выполняется
при значении life, равным true, но достаточно переменной life присвоить зна-
чение false, и потоковая функция завершит своё выполнение, закончив тем
самым и функционирование потока и потокового объекта.
Для координации параллельного совместного выполнения нескольких
потоков используются объекты синхронизации - мютексы (mutexes), мони-
торы (monitors) и события (events). Они позволяют выполняться в данный
момент ограниченному числу потоков, связанных с некоторым объектом-
разделяемым ресурсом, и приостанавливать потоки до свершения определен-
ных действий. Чтобы овладеть разделяемым ресурсом, потоки выстраивают-
ся в очередь.
Для отладки класса потоковых объектов в этот класс включим пере-
менную num - номер экземпляра конкретного объекта, а в цикл while пото-
ковой функции включим переменную n, определяющую номер цикла. Зна-
чения num и n, выданные на консоль, информируют о выполняющихся пото-
ковых объектах.
В нижеследующих примерах пояснено создание и использование пото-
ковых объектов. Особое внимание уделяется использованию событий пото-
ковыми объектами как для информирования об их выполнении, так и для
связи разных функционирующих потоковых объектов с помощью событий.
В примере 9.2.1 рассматривается параллельное выполнение двух пото-
ковых объектов.
Пример 9.2.1. Два параллельно выполняющихся потоковых объекта на
языке C#.
////////////////////
/ / C #
using System;
using System.Threading;
namespace CsTl_2
{
class CThread // Класс потокового объекта
int num; || Номер потокового объекта
Thread thread; // Ссылка на поток
bool run; // Признак выполнения потока
bool llfe; // Признак жизни потока
public CThread (lnt Num ) {num= Num; llfe= false; run= false;>
~CThread ( ) {llfe= false;>
public void Start ( ) // Стартовать потоковый объект
{
if (!life) // Если не жил, то
{
run= true; // пусть выполняется и
life= true; // живёт
Н Создать поток
thread= new Thread (new ThreadStart (ThreadFunc));
thread.Start ( ); || Запустить поток >
>
public vold Finish ( ) {life= false;}
public void Suspend ( ) // Приостановить потоковый объект
{
if (run) // Если выполнялся, то
{
run= false; // пусть не выполняется
thread.Suspend ( ); // Приостановить поток
>
>
public void Resume ( ) // Возобновить потоковый объект
{
if (irun) // Если не выполнялся, то
{
run= true; // пусть выполняется
thread.Resume ( ); // Возобновить поток >
>
private void ThreadFunc ( ) // Выполнить поток
{
int n= 0; // Номер цикла потока
while (llfe) // Пока живём, выполнять:
{
Console.WriteLine ("thread " + num + " n= " + n);
n++;
Thread.Sieep (50);
}
Console.WriteLine ("Thread " + num + " flnished");
class TestThread
{
static void Mairi ()
{
CThread threadl= new CThread (1); // Создать первый объект
CThread thread2= new CThread (2); // Создать второй объект
threadl.Start ( ); // Стартовать первый потоковый объект
thread2.Start (); // Стартовать второй потоковый объект
Thread.Sleep (100); // Поспать 100 мс
Console,WrlteLlne (" Приостановить поток первого объекта");
threadl.Suspend (); // Приостановить первый потоковый объект
Thread.Sleep (100); // Поспать 100 мс
Console.WriteLine (" Возобновить поток первого объекта");
threadl.Resume (); // Возобновить первый потоковый объект
Thread.Sleep (100); // Поспать 100 мс
Console.WriteLine (" Завершить потоки объектов");
threadl.Flnlsh (); // Завершить первый потоковый объект
thread2.Flnish ( ); // Завершить второй потоковый объект
>
>
////////////////////
// C++/CLI
#include "stdafx.h"
using namespace System;
using namespace System::Threading;
ref class CThread // Управляемый класс потокового объекта
{
int num;
Thread ^thread;
bool run;
bool life;
public:
CThread (int Num ) {num= Num; life= false; run= false;>
// Номер потокового объекта
// Дескриптор на поток
// Признак выполнения потока
// Признак жизни потока
-CThread ( ) <life= false;}
vold Start ( )
{
if(!life)
{
// Стартовать потоковый объект
// Если не живёт, то
run= true; // пусть живёт и
life= true; // выполняется
// Создать поток
thread= gcnew Thread (gcnew ThreadStart (this,
&CThread::ThreadFunc));
thread ->Start ( ); // Стартовать поток
void Finish ( ) <life= false; thread -> Join ( );}
vold Suspend ( ) // Приостановить потоковый объект
{
If (run) // Если выполняется, то
{
run= false; // не выполнять
thread -> Suspend ( ); // Приостановить поток
>
>
vold Resurne ( ) // Возобновить потоковый объект
{
if (!run) // Если не выполнялся, то
{
run= true; // выполнять
thread ->Resume ( ); // Возобновить поток
>
>
void ThreadFunc ( ) // Выполнить поток
{
int n= 0; // Номер цикла
while (llfe) // Если живём, то выполнять:
{
n++;
Console::Wrlte ("thread {0}", num.ToString ());
Console::WriteUne (" n= {0}", n.ToString ());
Thread::Sleep (50); >
Console::Write ('Thread {0>", num.ToString ());
Console::WrlteLine (" finished"); >
>;
void ma!n ()
{
CThread ^threadl= gcnew CThread (1); // Создать первый объект
CThread ^thread2= gcnew CThread (2); // Создать второй объект
threadl -> Start (); // Стартовать первый потоковый объект
thread2 -> Start ( ); // Стартовать второй потоковый объект
Thread::Sleep (100); // Поспать 100 мс
Console::WriteLine (" Приостановить поток первого объекта");
threadl -> Suspend (); // Приостановить первый потоковый объект
Thread::Sleep (100); // Поспать 100 мс
Console::WriteLine (" Возобновить поток первого объекта");
threadl -> Resume (); // Возобновить первый потоковый объект
Thread::Sleep (100); // Поспать 100 мс
Console::WrlteUne (" Завершить потоки объектов");
threadl -> Finish (); // Завершить первый потоковый объект
thread2 -> Finish (); // Завершить второй потоковый объект
/>*
Result:
thread 1 n= 1
thread 2 n= 1
thread 1 n= 2
thread 2 n= 2
Приостановить поток первого объекта
thread 2 n= 3
thread 2 n= 4
Возобновить поток первого объекта
thread 1 n= 3
thread 2 n= 5
thread 1 n= 4
tnread 2 n= 6
Завершить потоки объектов
Thread 1 finished
Thread 2 finished
*/
C#. Класс CThread потокового объекта содержит данные: num - номер экзем-
пляра потокового объекта, life - признак жизни потока, run - признак выпол-
нения потока и thread - ссылка на поток.
Поток thread является объектом класса Thread библиотеки .NET
Framework и создаётся с помощью оператора new в теле функции StartQ
класса CThread потокового объекта с обязательным предварительным при-
сваиванием переменной life значения true. Аргументом конструктора Thread
является объект потокового делегата ThreadStart, создаваемый также с помо-
щью оператора new. Конструктор делегата содержит в качестве аргумента
имя потоковой функции ThreadFunc(). Созданный поток thread запускается
посредством функции StartQ класса Thread.
Интерфейсные функции Start(), Suspend(), Resume() и Finish() потоко-
вого объекта обеспечивают его запуск, приостановку и возобновление функ-
ционирования, и завершение функционирования. Объявленная в классе пе-
ременная run используется функциями Suspend() и Resume() для переключе-
ния потока из приоетановленного состояния в состоянии выполнения, и на-
оборот.
Потоковая функция ThreadFunc(), выполняясь пока значение life равно
true, после каждого цикла while выдаёт на консоль строку вида:
thread номер-потокового-объекта n= номер-цикла
Столбик таких строк на консоли свидетельствует о выполнении циклов пото-
ковой функции потокового объекта.
Главная функция Main() приложения создаёт потоковые объекты
threadl и thread2 класса CThread. Конструктор класса CThread только создаёт
поток, связанный с этим объектом, и лишь после применения функции Start()
класса CThread к объектам threadl и thread2 эти объекты начинают функцио-
нировать. Потоки выполняются параллельно, о чём свидетельствует инфор-
мация, выданная на консоль: строки, выданные потоковыми функциями раз-
ных объектов, чередуются. Поспав 100 мс (причиной чего является вызов
функции Sleep()), основной поток, представленный главной функцией Main(),
позволяет этим объектам функционировать самостоятельно и выдать резуль-
тативную информацию на консоль. Затем к объекту threadl применяется
функция Suspend(), которая приостанавливает его функционирование. По-
скольку функция Sleep() опять задерживает выполнение основного потока, то
теперь выполняется только поток объекта thread2. О чём свидетельствуют
две выданные подряд строки объекта thread2 и отсутствие строк от объекта
threadl. Через 100 мс функция Resume() возобновляет приостановленное вы-
полнение объекта threadl. Теперь параллельно выполняются потоки обоих
объектов. А через 100 мс функция Finish(), применённая к объектам, завер-
шает их функционирование. Функция Finish() присваивает переменной life
значение false - цикл потоковых функций прекращается.
C++/CLI. Программа на языке C++/CLI очень схожа с программой на C#.
Прежде всего бросается в глаза присутствие ref в описании класса CThread.
Это связано с тем, что класс CThread должен бьггь управляемым, поскольку
он использует управляемый класс Thread и управляемый делегат ThreadStart
библиотеки .NET Framework.
Вместо ссылочной переменной в классе CThread объявлен дескриптор
thread на объект управляемого класса Thread. При ссылке на функции Start(),
Suspend(), Resume() класса Thread в функциях Start(), Suspend(), Resume()
нашего класса CThread использован этот дескриптор со стрелкой.
Также отличается получение объекта делегата в аргументе конструкто-
ра класса Thread при создании объекта потока.
Как видим, создание объектов с потоками не представляет сложности в
языках C# и C++/CLI. Использование потокового делегата существенно уп-
рощает создание в объекте множества потоков с разноимёнными потоковыми
функциями.
Заметим, что применение функций Suspend() и Resume() класса Thread
не рекомендуется при разработке многопоточных сложных программ, по-
скольку может привести к непредвидимым аварийным ситуациям при парал-
лельном выполнении потоков. В случае нашей простой программы использо-
вание этих функций допустимо. Как избежать применения функций
Suspend() и Resume() будет изложено в разделах книги, посвященных син-
хронизации параллельного выполнения потоков и в конце книги при рас-
смотрении разработки многопоточной программы.
