Главная страница
Навигация по странице:

  • МНОГОПОТОЧНОЕ ПРОГРАММИРОВАНИЕ

  • Класс Thread и создание потоков

  • Результат выполнения программы (из листинга 6.1)

  • Васильев А.Н. Основы программирования на C#. Васильев А. Н. Программирование


    Скачать 5.54 Mb.
    НазваниеВасильев А. Н. Программирование
    АнкорВасильев А.Н. Основы программирования на C
    Дата20.09.2022
    Размер5.54 Mb.
    Формат файлаpdf
    Имя файлаVasilev_Programmirovanie-na-C-dlya-nachinayushchih-Osobennosti-y.pdf
    ТипДокументы
    #686596
    страница22 из 40
    1   ...   18   19   20   21   22   23   24   25   ...   40
    Результат выполнения программы (из листинга 5.12)
    Ɂɧɚɱɟɧɢɟ ɫɜɨɣɫɬɜɚ: 100
    Ɂɧɚɱɟɧɢɟ ɫɜɨɣɫɬɜɚ: В классе MyClass для свойства number get-аксессор описан так, что результатом возвращается значение поля num. А вот в set-аксессоре использована конструкция try-catch. В блоке размещен блока в нем — команда num=(byte)value. Если при присваивании значения полю num будет иметь место переполнение, то сгенери- руется исключение класса OverflowException. Для обработки этого исключения предназначен блок, в котором командой num=255 полю num присваивается максимально возможное значение В главном методе программы командой MyClass obj=new MyClass() создается объект obj класса MyClass. Проверка показывает, что при выполнении команды obj.number=100 полю num присваивается значение, а при выполнении команды obj.number=300 это поле, как и ожидалось, получает значение Резюме Это твое заднее слово Заднее не бывает!
    из к/ф «Кин-дза-дза»
    • При возникновении ошибки в процессе выполнения программы она завершает свою работу. Существует возможность обработки подобных ситуаций. В этом случае используется конструкция try-catch
    • Если при выполнении кода в блоке try ошибок не было, то catch
    - блок игнорируется. Если при выполнении кода в блоке try возникла ошибка, то просматриваются блоки catch
    , связанные сданным Глава блоком try
    . Каждый блок предназначен для обработки ошибок определенного типа. Если подходящий блок найден, то выполняется код этого блока. Если нужный блок не найден, то ошибка передается для обработки во внешнюю конструкцию try-catch
    (если такая есть. Если ошибка не обработана, программа завершает свое выполнение В описании блока указывается класс ошибки, обрабатываемой в блоке. Блок обрабатывает ошибки данного класса, а также всех его подклассов. При необходимости в блоке можно объявить и использовать объект ошибки. Объект ошибки создается автоматически при возникновении ошибки Классы ошибок (исключений) образуют иерархию наследования. На вершине этой иерархии находится класс
    Exception
    . У него есть производные классы
    SystemException и
    ApplicationException
    (последний обычно используется при создании классов пользовательских исключений Конструкции try-catch могут быть вложенными. В таком случае, если исключение не обрабатывается во внутренней конструкции, оно передается во внешнюю конструкцию try-catch
    . Также можно использовать блок finally
    , который выполняется в обязательном порядке и при возникновении ошибки, и если ошибка не возникла Исключения могут генерироваться вручную. Для этого используют инструкцию throw
    , после которой указывается имя объекта исключения. Объект исключения можно создать самостоятельно или воспользоваться объектом, созданным автоматически при возникновении ошибки. Для повторного генерирования исключения в catch
    - блоке используют инструкцию throw
    , после которой объект исключения не указывается Допускается создавать собственные классы исключений. Такие классы создаются путем наследования классов
    Exception или
    ApplicationException
    • Инструкции checked и unchecked позволяют переходить в режим и выходить из режима контроля переполнения при выполнении арифметических операций
    Обработка исключений
    275
    Задания для самостоятельной работы
    Я не бездействовал. Я сразу на каппу нажал. Скрипач свидетель.
    из к/ф «Кин-дза-дза»
    1. Напишите программу, в которой пользователь вводит через консоль размер целочисленного массива. Массив создается, заполняется натуральными числами, а затем содержимое массива отображается в консольном окне. Предусмотреть обработку исключений, связанных стем, что пользователь ввел некорректное значение для размера массива или ввел нечисловое значение Напишите программу, в которой пользователь последовательно вводит два целых числа. Программа вычисляет остаток отделения большего числа на меньшее число. Программный код следует написать с учетом обработки возможных ошибок Напишите программу, в которой уравнение вида
    Ax = B решается на множестве целых чисел. Решением является такое целое число
    x, которое, будучи умноженным на целое число
    A, дает целое число B. Решение существует только в том случае, если целое число
    B без остатка делится на целое число
    A или если оба параметра A и B равны нулю. Предусмотреть обработку исключительных ситуаций Напишите программу, в которой решается квадратное уравнение
    Ax
    2
    +
    Bx + C = 0. В общем случае уравнение имеет два решения
    x =
    2A
    –B±B
    2
    4AC
    . Предложите схему обработки исключительных ситуаций. Для вычисления квадратного корня можно использовать статический метод Sqrt() из класса Math.
    5. Напишите программу, содержащую статический метод, первым аргументом которого является целочисленный массива вторым аргументом целочисленное значение. Методом при вызове выполняется проверка относительно наличия в массиве (первый аргумент) элемента со значением, определяемым вторым аргументом. Если такой элемент есть, то результатом возвращается индекс этого элемента (первого из них, если таких элементов несколько. Если элемента с указанным значением в массиве нетто метод генерирует исключение. Предложите способ проверки функциональности метода, включая обработку исключений Глава 5
    276
    6. Напишите программу, содержащую статический метод, не возвращающий результат. Аргументом методу передается целое число. Если число четное, то метод генерирует исключение класса
    ArithmeticException
    , а если число нечетное, то генерируется исключение класса OverflowException. В главном методе выполняется оператор цикла, в котором за каждый цикл пользователь вводит целое число, оно передается аргументом методу. Организовать обработку событий таким образом, чтобы в результате появлялось сообщение о том, четное число или нечетное. Оператор цикла должен завершать работу, если пользователь вводит не число Напишите программу, содержащую класс с индексатором. Через ин- дексатор можно получить доступ к элементам закрытого целочисленного массива. Используя обработку исключительных ситуаций, опишите статический метод, аргументом которому передается объект класса, аре- зультатом возвращается размер закрытого массива в этом объекте Напишите программу, в которой описывается класс для ошибки пользовательского типа. У класса должно быть поле, являющееся ссылкой на символьный массив. В качестве аргумента конструктору класса передается целое число, определяющее размер массива. Массив заполняется последовательностью букв (например, начиная с буквы
    ƍAƍ). В главном методе программы для реализации символьного массива создается объект исключения пользовательского класса. Для отображения содержимого массива искусственно генерируется исключение, а обработка исключения сводится к отображению содержимого массива из объекта исключения Напишите программу, в которой описаны два класса пользовательских исключений (один создается наследованием класса Exception, а другой создается наследованием класса ApplicationException). Опишите класс с закрытым символьным массивом и индексатором, который позволяет присваивать значения элементам массива и считывать значения элементов массива. Определите индексатор таким образом, чтобы при слишком большом индексе (выходящем за верхнюю границу) генерировалось исключение первого пользовательского класса исключений, а при отрицательном индексе генерировалось исключение второго пользовательского класса. В главном методе предложите механизм проверки функциональности индексатора для индексируемых объектов Напишите программу, содержащую класс с индексатором. При индексировании объекта в качестве значения соответствующего выражения
    Обработка исключений возвращается целое число и, соответственно, присваивается целое число типа int. Присваиваемые значения записываются в массив с элементами типа byte. Используя обработку исключительных ситуаций и инструкцию checked, опишите индексатор так, чтобы при попытке присвоить проиндексированному объекту значение, выходящее за допустимый диапазон для значений типа byte, соответствующий элемент массива получал значение 255.
    Глава 6
    МНОГОПОТОЧНОЕ
    ПРОГРАММИРОВАНИЕ
    На двух лошадях скакать — седалища не хватит!
    из к/ф Формула любви»
    Пришло время обсудить такой мощный и эффектный механизм, как
    многопоточное программирование. Нам предстоит узнать много нового и интересного. Среди тем, рассматриваемых далее, будут такие принципы реализации многопоточных приложений знакомство с классом
    Thread
    ;
    • создание дочерних потоков и способы управления ими получение доступа к объекту главного потока создание фоновых потоков знакомство с методами синхронизации.
    В процессе обсуждения этих тем мы будем также рассматривать примеры, которые поясняют и иллюстрируют способы практической реализации базовых концепций многопоточного программирования.
    Класс Thread и создание потоков
    Ох, тяжко мне Молви еще раз, тыне демон?
    из к/ф Иван Васильевич меняет профессию»
    Прежде чем приступить к рассмотрению вопросов, связанных с много- поточным программированием, имеет смысл уточнить, что же это такое. Вообще, потоками называются разные части программы, которые выполняются одновременно. Именно в одновременном выполнении

    Многопоточное программирование
    279
    нескольких блоков программного кода кроется изюминка многопо- точного программирования. В языке C# предусмотрены простые и эффективные средства для реализации многопоточного способа программирования. С этими средствами мы намерены познакомиться.
    Стратегическая задача состоит из двух подзадач. Во-первых, необходимо определить блоки программного кода, которые будут выполняться одновременно (код, выполняемый в потоке. Во-вторых, необходимо запустить эти коды на выполнение в специальном режиме (чтобы они выполнялись одновременно. Для запуска программного кода на выполнение в режиме потока нам понадобится специальный объект — объект потока. Создается такой объект на основе класса Thread.
    q
    ПОДРОБНОСТИ bКласс
    Thread определен в пространстве имен Класс
    Thread определен с инструкцией sealed
    . Это означает, что данный класс не может быть базовым для создания производных классов.
    Создание объекта потока не означает, что поток начинает выполняться. Для запуска потока на выполнение из объекта этого потока необходимо вызвать метод Start().
    q
    ПОДРОБНОСТИ bЕсли метод
    Start()
    вызывается из объекта потока, который уже запущенна выполнение, то генерируется исключение класса То есть здесь все относительно просто создаем объект класса Thread и вызываем из этого объекта метод Start(). Но открытым остается вопрос о том, как связать объект потока с программным кодом, который должен выполняться в потоке. Такое связывание происходит на этапе создания объекта потока. Происходит это так при создании объекта потока на основе класса Thread в качестве аргумента конструктору передается ссылка на экземпляр делегата ThreadStart. Предполагается, что экземпляр делегата содержит ссылку на метод или методы, которые будут вызваны при выполнении потока. Делегат ThreadStart определен для методов без аргументов, не возвращающих результат
    Глава 6
    280
    q
    ПОДРОБНОСТИ bПри создании объекта класса
    Thread аргументом конструктору можно передать ссылку на метод без аргументов, не возвращающий результат. Хотя формально аргументом конструктора должна быть ссылка типа
    ThreadStart
    , это работает. Принцип такой. Под аргумент конструктора выделяется переменная типа Значением этой переменной присваивается ссылка на метод. В результате создается экземпляр делегата, который ссылается на метода ссылка на экземпляр присваивается переменной, выделенной под аргумент конструктора.
    Если мы хотим, чтобы в потоке выполнялось несколько методов (последовательно, один за другим, то имеет смысл создать экземпляр делегата
    ThreadStart
    , записать в него ссылки на соответствующие методы, а ссылку на экземпляр передать аргументом конструктору класса
    Thread
    (при создании объекта потока).
    Простой пример, в котором в программе создается дочерний поток, представлен в листинге Листинг 6.1. Знакомство с потоками System;
    using System.Threading;
    //
    Ʉɥɚɫɫ ɫ ɝɥɚɜɧɵɦ ɦɟɬɨɞɨɦ:
    class ThreadDemo{
    //
    ɋɬɚɬɢɱɟɫɤɢɣ ɦɟɬɨɞ (ɞɥɹ ɜɵɡɨɜɚ ɜ ɞɨɱɟɪɧɟɦ ɩɨɬɨɤɟ):
    static void run(){
    Console.WriteLine(
    ƎɁɚɩɭɫɤɚɟɦ ɞɨɱɟɪɧɢɣ ɩɨɬɨɤƎ);
    //
    Ɉɩɟɪɚɬɨɪ ɰɢɤɥɚ:
    for(int k=0;k<=5;k++){
    //
    Ɉɬɨɛɪɚɠɟɧɢɟ ɫɨɨɛɳɟɧɢɹ:
    Console.WriteLine(
    ƎȾɨɱɟɪɧɢɣ ɩɨɬɨɤ: {0}Ǝ,(char)('A'+k));
    //
    Ɂɚɞɟɪɠɤɚ ɜɵɩɨɥɧɟɧɢɹ ɩɨɬɨɤɚ ɜ 1 ɫɟɤɭɧɞɭ:
    Thread.Sleep(1000);
    }
    Console.WriteLine(
    ƎȾɨɱɟɪɧɢɣ ɩɨɬɨɤ ɡɚɜɟɪɲɟɧƎ);
    }

    Многопоточное программирование //
    Ƚɥɚɜɧɵɣ ɦɟɬɨɞ:
    static void Main(){
    Console.WriteLine(
    ƎɁɚɩɭɫɤɚɟɦ ɝɥɚɜɧɵɣ ɩɨɬɨɤƎ);
    //
    ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɚ ɞɨɱɟɪɧɟɝɨ ɩɨɬɨɤɚ:
    Thread mt=new Thread(run);
    //
    Ɂɚɩɭɫɤ ɞɨɱɟɪɧɟɝɨ ɩɨɬɨɤɚ:
    mt.Start();
    //
    Ɉɩɟɪɚɬɨɪ ɰɢɤɥɚ:
    for(int k=1;k<=5;k++){
    //
    Ɉɬɨɛɪɚɠɟɧɢɟ ɫɨɨɛɳɟɧɢɹ:
    Console.WriteLine(
    ƎȽɥɚɜɧɵɣ ɩɨɬɨɤ: Ǝ+k);
    //
    Ɂɚɞɟɪɠɤɚ ɜɵɩɨɥɧɟɧɢɹ ɩɨɬɨɤɚ ɜ 2 ɫɟɤɭɧɞɵ:
    Thread.Sleep(2000);
    }
    Console.WriteLine(
    ƎȽɥɚɜɧɵɣ ɩɨɬɨɤ ɡɚɜɟɪɲɟɧƎ);
    Результат выполнения программы может быть таким:
    
    Результат выполнения программы (из листинга 6.1)
    Ɂɚɩɭɫɤɚɟɦ ɝɥɚɜɧɵɣ ɩɨɬɨɤ
    Ƚɥɚɜɧɵɣ ɩɨɬɨɤ: 1
    Ɂɚɩɭɫɤɚɟɦ ɞɨɱɟɪɧɢɣ ɩɨɬɨɤ
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ: A
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ: B
    Ƚɥɚɜɧɵɣ ɩɨɬɨɤ: 2
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ: C
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ: D
    Ƚɥɚɜɧɵɣ ɩɨɬɨɤ: 3
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ: E
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ: F
    Ƚɥɚɜɧɵɣ ɩɨɬɨɤ: 4
    Ⱦɨɱɟɪɧɢɣ ɩɨɬɨɤ ɡɚɜɟɪɲɟɧ
    Глава 6
    282
    Ƚɥɚɜɧɵɣ ɩɨɬɨɤ: 5
    Ƚɥɚɜɧɵɣ ɩɨɬɨɤ Программа достаточно простая. В главном классе описывается статический метод run(), который не возвращает результат и у которого нет аргументов (то есть этот метод соответствует библиотечному делегату
    ThreadStart
    ). Мы собираемся выполнять код метода run() в режиме дочернего потока. В теле метода командой Console.WriteLine(
    ƎɁɚ-
    ɩɭɫɤɚɟɦ ɞɨɱɟɪɧɢɣ ɩɨɬɨɤƎ) отображается сообщение о начале выполнения дочернего потока, после чего запускается оператор цикла, в котором индексная переменная k пробегает значения от 0 до 5 включительно, увеличивая каждый раз свое значение на единицу. За каждую итерацию цикла командой Console.WriteLine(
    ƎȾɨɱɟɪɧɢɣ ɩɨɬɨɤ: {0}Ǝ,(char)
    (
    ƍAƍ+k)) в консольном окне отображается сообщение, которое содержит очередную букву латинского алфавита, начиная с буквы
    ƍAƍ. После этого командой Thread.Sleep(1000) выполняется задержка в выполнении потока длительностью в 1 секунду. Здесь мы вызываем статический метод
    Sleep()
    из класса Thread. Действие метода состоит в том, что выполняется временная остановка в выполнении потока. Время приостановки потока определяется аргументом метода Sleep() и измеряется в миллисекундах секунда содержит 1000 миллисекунд НАЗ А МЕТКУ Таким образом, при выполнении метода run()
    в консольном окне отображаются сообщения, но отображаются они с интервалом в 1 секунду.
    После завершения оператора цикла командой Console.WriteLine(
    ƎȾɨ-
    ɱɟɪɧɢɣ ɩɨɬɨɤ ɡɚɜɟɪɲɟɧƎ) отображается сообщение о завершении выполнения потока НАЗ А МЕТКУ Для использования класса
    Thread в программе, кроме пространства имен
    System
    , подключается еще и пространство имен Выполнение программы начинается с выполнения главного метода. В главном методе программы командой Console.WriteLine(
    ƎɁɚ-
    ɩɭɫɤɚɟɦ ɝɥɚɜɧɵɣ ɩɨɬɨɤƎ) отображается сообщение о начале

    Многопоточное программирование
    283
    выполнения программы (главного потока. Затем с помощью команды
    Thread mt=new Thread(run) создается объект mt класса Thread. Это объект для дочернего потока. Аргументом конструктору передается имя метода run(). Следовательно, при выполнении потока, связанного с объектом mt, будет выполняться код метода run().
    q
    ПОДРОБНОСТИ bКонструктор класса
    Thread рассчитан на передачу в качестве аргумента ссылки на экземпляр делегата
    ThreadStart
    . Под эту ссылку выделяется соответствующая переменная (переменная типа делегата. По факту аргументом передается ссылка на метод. В результате переменной типа делегата присваивается ссылка на метод. Ситуация обрабатывается следующим образом создается экземпляр делегата, ссылающийся на данный метода ссылка на экземпляр делегата записывается в переменную делегата. Поэтому вместо создания экземпляра делегата и передачи ссылки на этот экземпляр конструктору класса
    Thread мы можем сразу передать аргументом конструктору ссылку на метод.
    Но сам по себе факт создания объекта потока не означает, что поток начинает выполняться. Поток следует запустить на выполнение. Для этого из объекта потока вызывается метод Start() (команда mt.Start()
    ). В этот момент запускается дочерний поток начинает выполняться метод run(). Но поскольку он выполняется в дочернем потоке, то следующая команда в главном потоке начинает выполняться, не дожидаясь окончания выполнения метода run(). В главном потоке выполняется оператор цикла. На каждой итерации цикла командой
    Console.WriteLine(
    ƎȽɥɚɜɧɵɣ ɩɨɬɨɤ: Ǝ+k) отображается сообщение со значением индексной переменной k. Затем командой Thread.
    Sleep(2000)
    выполняется задержка в 2 секунды в выполнении главного потока. По завершении оператора цикла в главном потоке командой
    Console.WriteLine(
    ƎȽɥɚɜɧɵɣ ɩɨɬɨɤ ɡɚɜɟɪɲɟɧƎ) в консольном окне отображается сообщение НАЗ А МЕТКУ Получается, что главный и дочерний потоки одновременно отображают сообщения в консольном окне. Но для дочернего потока интервал между сообщениями составляет 1 секунду, а главный поток выводит сообщения с интервалом в 2 секунды. Понятно, что дочерний поток завершает работу раньше главного потока
    Глава Использование потоков
    Кому чего в городе купить Принимаю заказы до одной тонны.
    из к/ф «Девчата»
    Далее мы рассмотрим различные способы создания потоков в программе. Еще одна программа иллюстрирует подход, при котором в программе создается несколько дочерних потоков, причем на этот раз программный код потоков реализуется на основе нестатических методов. Рассмотрим код в листинге Листинг 6.2. Несколько дочерних потоков System;
    using System.Threading;
    //
    Ʉɥɚɫɫ ɫ ɦɟɬɨɞɨɦ ɞɥɹ ɜɵɩɨɥɧɟɧɢɹ ɜ ɩɨɬɨɤɟ:
    class MyClass{
    //
    Ʉɨɥɢɱɟɫɬɜɨ ɫɨɨɛɳɟɧɢɣ:
    private int count;
    //
    ȼɪɟɦɹ ɡɚɞɟɪɠɤɢ ɦɟɠɞɭ ɫɨɨɛɳɟɧɢɹɦɢ:
    private int time;
    //
    Ɍɟɤɫɬ ɞɥɹ ɨɬɨɛɪɚɠɟɧɢɹ:
    private string text;
    //
    Ɇɟɬɨɞ ɞɥɹ ɜɵɩɨɥɧɟɧɢɹ ɜ ɩɨɬɨɤɟ:
    public void show(){
    Console.WriteLine(text+
    Ǝ: ɇɚɱɚɥɨ...Ǝ);
    for(int i=1;i<=count;i++){
    //
    Ɉɬɨɛɪɚɠɟɧɢɟ ɫɨɨɛɳɟɧɢɹ:
    Console.WriteLine(text+
    Ǝ -> Ǝ+i);
    //
    Ɂɚɞɟɪɠɤɚ ɜ ɜɵɩɨɥɧɟɧɢɢ ɩɨɬɨɤɚ:
    Thread.Sleep(time);
    }
    Console.WriteLine(text+
    Ǝ: Ɂɚɜɟɪɲɟɧɢɟ...Ǝ);
    }

    Многопоточное программирование //
    Ʉɨɧɫɬɪɭɤɬɨɪ:
    public MyClass(int c,int t,string txt){
    count=c;
    time=t;
    text=txt;
    }
    }
    //
    Ƚɥɚɜɧɵɣ ɤɥɚɫɫ:
    class ManyThreadsDemo{
    //
    Ƚɥɚɜɧɵɣ ɦɟɬɨɞ:
    static void Main(){
    Console.WriteLine(
    ƎȽɥɚɜɧɵɣ ɩɨɬɨɤ: ɇɚɱɚɥɨ...Ǝ);
    //
    ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɨɜ:
    MyClass objA=new MyClass(5,2000,
    Ǝɉɨɬɨɤ AƎ);
    MyClass objB=new MyClass(6,1200,
    Ǝɉɨɬɨɤ BƎ);
    MyClass objC=new MyClass(8,1000,
    Ǝɉɨɬɨɤ CƎ);
    //
    ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɨɜ ɩɨɬɨɤɨɜ:
    Thread A=new Thread(objA.show);
    Thread B=new Thread(objB.show);
    Thread C=new Thread(objC.show);
    //
    Ɂɚɩɭɫɤ ɞɨɱɟɪɧɢɯ ɩɨɬɨɤɨɜ:
    A. Start();
    B. Start();
    C. Start();
    Console.WriteLine(
    ƎȽɥɚɜɧɵɣ ɩɨɬɨɤ: Ɂɚɜɟɪɲɟɧɢɟ...Ǝ);
    Ниже показан возможный результат выполнения программы:
    
    1   ...   18   19   20   21   22   23   24   25   ...   40


    написать администратору сайта