Создание и завершение потоков
В этом примере демонстрируется создание вспомогательного или рабочего потока и использование его для выполнения обработки параллельно с основным потоком. Также демонстрируется постановка одного потока в ожидание другого и корректное закрытие потока.
В примере создается класс с именем Worker, содержащий метод DoWork, который будет выполняться рабочим потоком. Это, по существу, функция Main для рабочего потока. Выполнение рабочего потока начнется с вызова этого метода, а завершение происходит автоматически при возврате из метода. Метод DoWork выглядит следующим образом:
---
Класс Worker содержит дополнительный метод, который указывает, что DoWork должен выполнить возврат. Этот метод называется RequestStop и выглядит следующим образом:
public void RequestStop() { _shouldStop = true; } |
Метод RequestStop присваивает элементу данных _shouldStop значение true. Так как этот элемент данных проверяется методом DoWork, это действие косвенно влияет на выполнение возврата DoWork, в результате чего рабочий поток закрывается. Однако следует обратить внимание на то, что DoWork и RequestStop будут выполняться различными потоками. DoWork выполняется рабочим потоком, а RequestStop выполняется основным потоком, поэтому _shouldStop элемент данных объявляется volatile следующим образом:
private volatile bool _shouldStop; |
Ключевое слово volatile предупреждает компилятор о том, что элемент данных _shouldStop будет использоваться несколькими потоками и, следовательно, не следует делать предположений оптимизации о состоянии данного элемента.
The use of volatile with the _shouldStop data member enables you to safely access this member from multiple threads without the use of formal thread synchronization techniques, but only because _shouldStop is a bool. This means that only single, atomic operations are necessary to modify _shouldStop. If, however, this data member were a class, struct, or array, accessing it from multiple threads would likely cause intermittent data corruption. Consider a thread that changes the values in an array. Windows regularly interrupts threads in order to allow other threads to execute. Therefore, this thread could be stopped after assigning some array elements but before assigning others. Because the array now has a state that the programmer never intended, another thread that reads this array may fail.
Before actually creating the worker thread, the Main function creates a Worker object and an instance of Thread. The thread object is configured to use the Worker.DoWork method as an entry point by passing a reference to this method to the Thread constructor, like this:
Worker workerObject = new Worker(); Thread workerThread = new Thread(workerObject.DoWork); |
At this point, although the worker thread object exists and is configured, the actual worker thread has not yet been created. This does not occur until Main calls the Start method:
workerThread.Start(); |
At this point the system initiates the execution of the worker thread, but it does so asynchronously to the primary thread. This means that the Main function continues to execute code immediately while the worker thread simultaneously undergoes initialization. To ensure that the Main function does not try to terminate the worker thread before it has a chance to execute, the Main function loops until the IsAlive property of the worker thread object is set to true:
while (!workerThread.IsAlive); |
Next, the primary thread is stopped briefly with a call to Sleep. This ensures that the worker thread's DoWork function will execute the loop inside the DoWork method for several iterations before the Main function executes more commands:
Thread.Sleep(1); |
After one millisecond elapses, Main signals to the worker thread object that it should terminate by using the Worker.RequestStop method introduced previously:
workerObject.RequestStop(); |
Использование ключевого слова volatile с элементом данных _shouldStop позволяет безопасно осуществлять доступ к этому элементу из нескольких потоков, не используя формальные методы синхронизации потоков, но только потому что _shouldStop является bool. Это означает, что только одинарные, атомарные операции необходимы для изменения _shouldStop. Если, однако, этот элемент данных являлся классом, структурой или массивом, использование его несколькими потоками скорее всего приведет к периодическому повреждению данных. Рассмотрим поток, изменяющий значения в массиве. Windows регулярно прерывает потоки, чтобы позволить другим потокам выполняться. Следовательно, этот поток будет остановлен после присваивания значений только некоторых элементов массива, до присваивания значений остальных. Так как текущее состояние массива не планировалось программистом, у другого потока может не удаться прочитать этот массив.
Перед тем, как фактически создать рабочий поток, функция Main создает объект Worker и экземпляр Thread. Объект потока конфигурируется для использования метода Worker.DoWork в качестве точки входа путем передачи ссылки на этот метод конструктору Thread следующим образом:
----
Хотя на этом этапе объект рабочего потока существует и уже настроен, фактический рабочий поток еще не создан. Этого не происходит до тех пор, пока Main не вызовет метод Start:
workerThread.Start(); |
На этом этапе система запускает выполнение рабочего потока, которое является асинхронным по отношению к основному потоку. Это означает, что функция Main продолжает немедленное выполнение кода, а рабочий поток одновременно проходит инициализацию. Чтобы функция Main не пыталась завершить рабочий поток до начала его выполнения, функция Main выполняется циклично до тех пор, пока свойству IsAlive рабочего потока не будет присвоено значение true:
while (!workerThread.IsAlive); |
Далее основной поток кратковременно останавливается вызовом Sleep. Это гарантирует выполнение функцией DoWork рабочего потока цикла внутри метода DoWork в течение нескольких итераций до того, как функция Main выполнит несколько команд:
Thread.Sleep(1); |
После того, как пройдет одна миллисекунда, Main передает объекту рабочего потока сигнал о завершении с использованием метода Worker.RequestStop, введенного ранее:
workerObject.RequestStop(); |
It is also possible to terminate a thread from another thread by using a call to Abort. This forcefully terminates the affected thread even if it has not completed its task and provides no opportunity for the cleanup of resources. The technique shown in this example is preferred.
Finally, the Main
function calls the Join method on the worker thread object. This method causes the current thread to block, or wait, until the thread that the object represents terminates. Therefore Join will not return until the worker thread returns, thereby terminating itself:
workerThread.Join(); |
At this point only the primary thread executing Main
exists. It displays one final message, and then returns, terminating the primary thread also.
Here is the complete example.
Example
using System; using System.Threading;
public class Worker { // This method will be called when the thread is started. public void DoWork() { while (!_shouldStop) { Console.WriteLine("worker thread: working..."); } Console.WriteLine("worker thread: terminating gracefully."); } public void RequestStop() { _shouldStop = true; } // Volatile is used as hint to the compiler that this data // member will be accessed by multiple threads. private volatile bool _shouldStop; } |
Также можно завершить поток из другого потока, используя вызов Abort. При этом выбранный поток принудительно завершается, даже если его задача еще не выполнена, причем возможности очистки ресурсов не предоставляется. Рекомендуется использовать метод, показанный в этом примере.
В завершение, функция Main
вызывает метод Join в объекте рабочего потока. Этот метод приводит к блокировке или ожиданию текущего потока до тех пор, пока не будет завершен поток, представляемый объектом. Следовательно, Join не возвращается до тех пор, пока не возвращается рабочий поток, таким образом завершая себя:
workerThread.Join(); |
На этом этапе существует только основной поток, выполняющий Main
. Функция выводит на экран последнее сообщение и возвращается, завершая при этом основной поток.
Ниже приведен полный пример.
Пример
---
public class WorkerThreadExample { static void Main() { // Create the thread object. This does not start the thread. Worker workerObject = new Worker(); Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread. workerThread.Start(); Console.WriteLine("main thread: Starting worker thread...");
// Loop until worker thread activates. while (!workerThread.IsAlive);
// Put the main thread to sleep for 1 millisecond to // allow the worker thread to do some work: Thread.Sleep(1);
// Request that the worker thread stop itself: workerObject.RequestStop();
// Use the Join method to block the current thread // until the object's thread terminates. workerThread.Join(); Console.WriteLine("main thread: Worker thread has terminated."); } } |
Here is the output:
main thread: starting worker thread... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: working... worker thread: terminating gracefully... main thread: worker thread has terminated |
----
Ниже приведены выходные данные:
-------
How to: Synchronize a Producer and a Consumer Thread
The following example demonstrates thread synchronization between the primary thread and two worker threads by using the lock keyword, and the AutoResetEvent and ManualResetEvent classes.
The example creates two auxiliary, or worker threads. One thread produces elements and stores them in a generic queue that is not thread-safe. The other thread consumes items from this queue. In addition, the primary thread periodically displays the contents of the queue, so that the queue is accessed by three threads. The lock keyword is used to synchronize access to the queue to ensure that the state of the queue is not corrupted.
In addition to simply preventing simultaneous access that uses the lock keyword, additional synchronization is provided by two event objects. One is used to signal the worker threads to terminate, and the other is used by the producer thread to signal to the consumer thread when a new item has been added to the queue. These two event objects are encapsulated in a class named SyncEvents. This lets the events pass to the objects that represent the consumer and producer threads easily. The SyncEvents class is defined as follows:
public class SyncEvents { public SyncEvents() {
_newItemEvent = new AutoResetEvent(false); _exitThreadEvent = new ManualResetEvent(false); _eventArray = new WaitHandle[2]; _eventArray[0] = _newItemEvent; _eventArray[1] = _exitThreadEvent; }
public EventWaitHandle ExitThreadEvent { get { return _exitThreadEvent; } } public EventWaitHandle NewItemEvent { get { return _newItemEvent; } } public WaitHandle[] EventArray { get { return _eventArray; } } private EventWaitHandle _newItemEvent; private EventWaitHandle _exitThreadEvent; private WaitHandle[] _eventArray; } |
- Оглавление
- Метод Main
- Ввод и вывод
- Компиляция и выполнение
- Общая структура программы на c#
- Main() и аргументы командной строки
- Общие сведения
- Аргументы командной строки
- Отображение аргументов командной строки
- Доступ к аргументам командной строки с помощью оператора "foreach"
- Значения, возвращаемые методом Main()
- Пример результатов выполнения
- Общие сведения о типах данных
- Приведение
- Результат
- Упаковка-преобразование и распаковка-преобразование3
- Производительность
- Упаковка-преобразование4
- Описание5
- Результат
- Распаковка-преобразование6
- Описание7
- Результат
- Преобразование массива байтов в значение типа "int"8
- Пример9
- Преобразование строки в значение типа "int"
- Преобразование шестнадцатеричных строк10
- Массивы
- Общие сведения о массивах
- Массивы как объекты
- Результат
- Одномерные массив
- Массивы типов значений и ссылочных типов.
- Многомерные массивы
- Инициализация массива
- Массивы массивов
- Результат
- Использование оператора foreach с массивами
- Передача массивов в качестве параметров
- Передача одномерных массивов в качестве параметров
- Пример 1 Описание
- Результат 1
- Передача многомерных массивов в качестве параметров
- Пример 2 Описание
- Передача массивов при помощи параметров ref и out
- Пример 1
- Пример 2
- Неявно типизированные массивы11
- Неявно типизированные массивы в инициализаторах объектов12
- Использование строк
- Работа со строками Escape-знаки
- Точные строки: символ @
- Доступ к отдельным знакам
- Смена регистра
- Сравнения
- Разделение строки на подстроки
- Строки с нулевыми значениями и пустые строки
- Использование класса StringBuilder13
- Анализ строк с помощью метода разделения
- Навигация по содержимому строки с помощью строковых методов
- Анализ строк с помощью регулярных выражений14
- Объединение нескольких строк
- Изменение содержимого строки
- Определение наличия числового значения в строке
- Надежное программирование
- Безопасность
- Базовые типы кодировки
- Типы форматирования
- Общие сведения о форматировании
- Описатели формата
- Анализ и описатели формата
- Метод ToString и описатели формата
- Поставщики формата15
- Составное форматирование
- Форматирование базовых типов
- Форматирование для различных языков и региональных параметров16
- Составное форматирование
- Строка составного формата
- Синтаксис элементов форматирования
- Выравнивание
- Компонент строки формата
- Оформление фигурных скобок17
- Порядок обработки18
- Примеры кода
- Строки числовых форматов
- Строки стандартных числовых форматов
- Примечания Настройки панели управления
- Свойства NumberFormatInfo
- Целочисленные типы и типы с плавающей запятой
- Бесконечности действительных чисел с плавающей запятой и NaN
- Строки настраиваемых числовых форматов19
- Примечания Бесконечности действительных чисел с плавающей запятой и NaN
- Настройки панели управления
- Строки формата с фиксированной запятой и округлением
- Разделители секций и условное форматирование20
- Два примера настраиваемых форматов
- Регулярные выражения в .Net Framework
- Регулярные выражения как язык
- Escape-знаки
- Выполнение действия со строками с помощью основных строковых операций
- Разбор строк
- Разбор числовых строк
- Операторы и выражения
- Операторы
- Выражения
- Литералы и простые имена
- Выражения вызова
- Операторы
- Анонимные функции
- Эволюция делегатов в c#
- Лямбда-выражения22
- Выражения-лямбды
- Лямбды операторов
- Лямбды со стандартными операторами запросов
- Вывод типа в лямбда-выражениях
- Область действия переменной в лямбда-выражениях
- Использование лямбда-выражений вне linq
- Анонимные методы
- Заметки
- Перегружаемые операторы
- Операторы преобразования23
- Общие сведения об операторах преобразования
- Использование операторов преобразования
- Пример 1 Описание
- Результат 1
- Пример 2 Описание
- Результат 2
- Реализация определенных пользователем преобразований между структурами
- Надежное программирование
- Перегрузка операторов для реализации класса комплексных чисел
- Переопределение Equals
- Объекты, классы и структуры
- Интерфейсы
- Универсальные типы
- Статические типы
- Объекты
- Экземпляры структуры и экземпляры класса
- Идентификация объекта и идентификация значения26
- Объявление классов
- Создание объектов
- Наследование классов
- Описание
- Результат
- Общие сведения о классах
- Структуры
- Общие сведения о структурах
- Использование структур
- Пример 1 Описание
- Результат
- Пример 2 Описание
- Результат
- Наследование
- Абстрактные и запечатанные классы и члены классов
- Абстрактные классы и члены классов
- Запечатанные классы и члены классов
- Определение абстрактных свойств
- Полиморфизм
- Общие сведения о полиморфизме
- Управление версиями с помощью ключевых слов "Override" и "New"
- Переопределение и выбор метода29
- Использование ключевых слов "Override" и "New"
- Переопределение метода ToString
- Порядок переопределения метода OnString в классе или структуре
- Интерфейсы
- Общие сведения об интерфейсах
- Явная реализация интерфейса33
- Явная реализация членов интерфейса
- Надежное программирование
- Явная реализация членов интерфейса с наследованием
- Надежное программирование
- Параметры методов
- Возвращаемые значения
- Передача параметров
- Передача параметров типа значения
- Пример. Передача типов значений с помощью значения.
- Пример. Передача типов значений с помощью ссылки.
- Пример. Замена типов значений.
- Передача параметров ссылочного типа
- Пример. Передача ссылочных типов по значению
- Результат
- Рассмотрение кода
- Пример. Передача ссылочных типов по ссылке
- Результат
- Рассмотрение кода
- Пример. Перестановка двух строк
- Результат
- Рассмотрение кода
- Конструкторы
- Использование конструкторов
- Конструкторы экземпляров
- Пример 1
- Результат
- Пример 2
- Результат
- Пример 3
- Результат
- Закрытые конструкторы35
- Результат
- Статические конструкторы36
- Результат
- Создание конструктора копии
- Деструкторы
- Заметки
- Использование деструкторов для освобождения ресурсов.
- Высвобождение ресурсов явным образом
- Результат
- Инициализаторы объектов и коллекций
- Инициализаторы объектов и анонимные типы37
- Инициализаторы объектов и типы, допускающие значение null
- Инициализаторы коллекций
- Инициализация объектов без вызова конструктора
- Компиляция кода38
- Инициализация словаря с помощью инициализатора коллекции39
- Компиляция кода
- Константы
- Вложенные типы
- Модификаторы доступа
- Доступность класса и структуры
- Доступность члена класса и структуры
- Другие типы
- Разделяемые классы и методы40
- Разделяемый класс
- Ограничения
- Пример 1 Описание
- Результат
- Пример 2 Описание
- Разделяемые методы
- Статические классы и члены статических классов
- Статические классы
- Когда следует использовать статические классы
- Статические члены
- Входные данные
- Пример результатов выполнения.
- Определение различия между передачей структуры и ссылки класса в метод
- Анонимные типы41
- Заметки
- Возвращение поднаборов свойств элементов в запросе
- Компиляция кода
- Методы расширения
- Неявно типизированные локальные переменные
- Var и анонимные типы
- Заметки
- Свойства
- Результат
- Общие сведения о свойствах
- Использование свойств
- Метод доступа get
- Метод доступа set
- Заметки
- Пример 1 Описание
- Результат 1 Employee number: 101 Employee name: Claude Vige
- Пример 2 Описание
- Результат 2
- Рассмотрение кода
- Пример 3 Описание
- Введенные данные
- Результат 3
- Свойства интерфейса
- Пример результатов выполнения
- Асимметричные методы доступа
- Ограничения модификаторов доступа в методах доступа
- Модификаторы доступа в переопределяющих методах доступа
- Реализация интерфейсов
- Домен доступности к методу доступа
- Результат
- Примечания
- Объявление и использование свойств чтения и записи
- Надежное программирование
- Автоматически реализуемые свойства
- Реализация облегченного класса с автоматически реализуемыми свойствами
- Индексаторы
- Общие сведения об индексаторах
- Использование индексаторов
- Заметки
- Пример 1 Описание
- Индексирование с использованием других значений
- Пример 2 Описание
- Результат
- Надежное программирование
- Индексаторы в интерфейсах
- Результат
- Сравнение свойств и индексаторов
- Делегаты
- Общие сведения о делегатах
- Использование делегатов
- Делегаты с именованными методами и делегаты с анонимными методами
- Заметки
- Пример 1
- Результат
- Пример 2
- Результат
- Использование делегатов вместо интерфейсов
- Ковариация и контрвариация в делегатах
- Пример 1 (ковариация) Описание
- Пример 2 (контрвариация) Описание
- Объединение делегатов (многоадресные делегаты)
- Объявление, создание экземпляра и использование делегата
- Надежное программирование
- События
- Общие сведения о событиях
- Подписка и отмена подписки на события
- Подписка на события в среде ide Visual Studio
- Подписка на события программными средствами
- Подписка на события при помощи анонимного метода
- Отмена подписки
- Отмена подписки на событие
- Публикация событий, соответствующих рекомендациям .Net Framework
- Порядок публикации событий, основанных на шаблоне EventHandler
- Создание событий базового класса в производных классах
- Вызов и прием событий
- Реализация событий интерфейса
- Реализация событий интерфейса в классе
- Пример44
- Использование словаря для хранения экземпляров событий
- Универсальные шаблоны
- Общие сведения об универсальных шаблонах
- Введение в универсальные шаблоны
- Преимущества универсальных шаблонов
- Параметры универсального типа
- Рекомендации по именованию параметра типа
- Пространства имен
- Общие сведения о пространствах имен
- Использование пространств имен
- Доступ к пространствам имен
- Псевдонимы пространств имен
- Использование пространств имен для управления областью действия
- Полные имена
- Использование квалификатора псевдонима пространства имен
- Типы, допускающие значения null
- Общие сведения о типах, допускающих значения null
- Использование типов, допускающих значение null
- Примеры допускающих значение null типов
- Члены допускающих значение null типов
- Явные преобразования
- Неявные преобразования
- Операторы
- Оператор ??
- Идентификация типа, допускающего значение null
- Небезопасный код и указатели
- Общие сведения о небезопасном коде
- Буферы фиксированного размера
- Заметки
- Типы указателей45
- Преобразования указателей
- Неявные преобразования указателей
- Явные преобразования указателей
- Результат
- Выражения указателей Получение значения переменной указателя
- Получение адреса переменной
- Доступ к члену с использованием указателя
- Доступ к элементу массива с использованием указателя
- Управление указателями Увеличение и уменьшение указателей
- Арифметические операции над указателями
- Сравнение указателей
- Использование указателей для копирования массива байтов
- Комментарии xml-документации
- Рекомендуемые теги для комментариев документации
- Использование xml-документации
- Компиляция кода
- Надежное программирование
- Домены приложений
- Общие сведения о доменах приложений
- Выполнение кода в другом домене приложения
- Сборки и глобальный кэш сборок
- Общие сведения о сборках
- Атрибуты
- Общие сведения об атрибутах
- Использование атрибутов
- Общие атрибуты
- Заметки
- Использование нескольких идентификаторов
- Атрибут Obsolete
- Глобальные атрибуты
- Исключения и обработка исключений
- Общие сведения об исключениях
- Использование исключений
- Обработка исключений
- Блоки catch
- Блоки finally
- Создание и генерация исключений
- Чего следует избегать при генерации исключений
- Определение классов исключений
- Исключения, создаваемые компилятором
- Обработка исключений с помощью блока try-catch
- Примечания
- Выполнение кода очистки с использованием блока finally
- Взаимодействие
- Использование вызова неуправляемого кода для воспроизведения звукового файла
- Компиляция кода Чтобы скомпилировать этот код, выполните следующие действия47
- Создание потоков
- Общие сведения
- Использование потоков
- Синхронизация потоков
- Ключевое слово lock
- Мониторы
- События синхронизации и дескрипторы ожидания
- Мьютексные объекты
- Создание и завершение потоков
- Синхронизация потока-производителя и потока-потребителя
- Использование пула потоков
- Отражение
- Общие сведения об отражении
- Библиотеки c#
- Создание и использование библиотек dll на языке c#
- Выполнение
- Результат
- Компиляция кода
- Безопасность
- Рекомендации по безопасности, касающиеся языка c# в отдельности
- Использование неуправляемых функций dll
- Применение экспортированных функций dll
- Подробный обзор вызова неуправляемого кода
- Идентификация функций в библиотеках dll
- Создание класса, содержащего функции dll
- Создание прототипов в управляемом коде
- Основы описания
- Настройка описания
- Задание точки входа
- Вызов функции dll
- Передача структур
- Объявление и передача структур
- Объявление и передача классов
- Файловый и потоковый ввод-вывод
- Основы файлового ввода-вывода
- Классы, используемые в файловом вводе и выводе
- Классы, используемые для чтения и записи в поток
- Общие классы потокового ввода и вывода
- Ввод-вывод и безопасность
- Создание списка каталогов
- Надежное программирование
- Считывание из нового файла данных и запись в этот файл
- Надежное программирование
- Копирование каталогов
- Открытие файла журнала и добавление в него данных
- Запись текста в файл
- Считывание текста из файла
- Надежное программирование
- Считывание символов из строки
- Результат
- Запись символов в строку
- Надежное программирование
- Добавление или удаление записей списка управления доступом
- Чтобы добавить или удалить элемент списка управления доступом из файла
- Чтобы добавить или удалить элемент acl из каталога
- Компиляция кода
- Сжатие файлов
- Создание потоков
- Создание класса Writer
- Коллекции и структуры данных
- Определение коллекций
- Выбор класса коллекции
- Знакомство с решениями, проектами и элементами
- Контейнеры: проекты и решения
- Элементы: файлы, ссылки, подключения к данным
- Решения как контейнеры
- Решения
- Преимущества
- Файлы определения
- Проекты как контейнеры
- Шаблоны проектов
- Файлы проекта
- Элементы проектов
- Использование интегрированной среды разработки Visual c#
- Введение в интегрированную среду разработки
- Средства Visual c#
- Доступ к средствам в интегрированной среде разработки
- Окна редактора и конструктора форм Windows
- Обозреватель решений и конструктор проектов
- Окна компилятора, отладчика и списка ошибок
- Настройка интегрированной среды разработки
- Создание проекта
- Создание нового проекта
- Состав проекта Свойства
- Ресурсы
- Другие файлы исходного кода
- Изменение свойств проекта
- Создание пользовательского интерфейса
- Добавление элементов управления
- Задание свойств
- Обработка событий
- Редактирование кода
- Списки завершения
- Краткие сведения
- Список членов
- Сведения о параметрах
- Добавление директив using
- Оптимизация кода
- Фрагменты кода
- Подчеркивание волнистой линией
- Средства обеспечения удобочитаемости кода Форматирование кода
- Структура
- Выделение цветом
- Навигация и поиск
- Представление классов
- Навигация ctrl-tab
- Панели переходов
- Поиск в файлах
- Обозреватель объектов
- Стеки навигации
- Построение и отладка
- Параметры построения
- Ошибки построения
- Сравнение отладочной и выпускной конфигураций
- Отладка
- Моделирование и анализ кода
- Конструктор классов
- Обозреватель объектов
- Метаданные как источник
- Анализ управляемого кода
- Добавление и редактирование ресурсов
- Добавление ресурсов в проекты
- Редактирование ресурсов
- Компиляция ресурсов в сборки
- Доступ к ресурсам во время выполнения
- Получение справки
- Локальная справка и справка в Интернете
- Поиск по f1
- Указатель
- Содержание
- Инструкции
- Динамическая справка
- Примеры
- Оптимизация
- Многопроектная оптимизация
- Диалоговое окно "Предварительный просмотр изменений"
- Допускающая наличие ошибок оптимизация
- Извлечение метода
- Оптимизация кода с помощью операции "извлечение метода"
- Чтобы воспользоваться операцией "извлечение метода"
- Переименовать
- Операции переименования
- Переименование идентификаторов
- Чтобы переименовать идентификатор
- Превращение локальной переменной в параметр
- Заметки
- Превращение локальной переменной в параметр
- Чтобы выполнить превращение локальной переменной в параметр
- Разметка кода цветом
- Лексемы
- Контекстные ключевые слова
- Разметка цветом для обозначения парности фигурных скобок
- Разметка цветом и жирным шрифтом
- Разметка цветом и выделение цветным фоном