Глава 1. Что такое потоки (threads)? Для чего их использовать?
Содержание:
Из истории.
На заре компьютерной эры все программирование было в основном однопоточным. Вы
создавали программу, пробивая дырочки в перфокартах или ленте, относили стопку
карт в местный вычислительный центр, и через несколько дней получали другую стопку,
в удачных случаях содержащую требуемые результаты. Вся обработка велась по принципу
- что раньше поступило, раньше выполняется, и при запуске вашей программы она
одна использовала компьютерное время.
Но все меняется. Концепция многопоточного исполнения впервые появилась на системах
с разделением времени (time sharing), где несколько человек могли одновременно
работать на центральном компьютере. Важно отметить, что процессорное время просто
делилось между пользователями, а уже сама операционная система использовала
концепции "процессов" и "потоков". Настольные компьютеры
прошли тот же путь. Раньше DOS и Windows были однозадачными. На компьютере могла
исполняться лишь единственная программа. С усложнением приложений и ростом требований
к персональному компьютеру, особенно в отношении высокой производительности
графики и сетевых возможностей, потребовались многопроцессные и многопоточные
операционные системы.
Определения.
Сначала определим, что называется процессом. Большинство пользователей
Windows 95, 98 и NT имеют об этом хорошее интуитивное представление. Они рассматривают
процесс как программу, которая выполняется на машине, сосуществуя и разделяя ресурсы
процессора, диска и памяти с другими программами. Программисты знают, что процесс
- это вызов исполняемого кода, причем этот код уникален и его инструкции выполняются
в определенном порядке. В общем, процессы изолированы. Используемые ими ресурсы
(память, диск, ввод-вывод,процессорное время) виртуальны, так что каждый процесс
имеет свой набор ресурсов, не разделяя их с другими, что обеспечивается операционной
системой. Процессы выполняют модули кода. Они могут быть раздельными, например,
модули кода Windows Explorer и Microsoft Word - различны. Однако они могут быть
и общими, как в случае библиотек DLL. Код DLL обычно исполняется во многих процессах,
и часто одновременно. Выполнение инструкций в целом для разных процессов не упорядочено:
Microsoft Word не останавливает открытие документа во время посылки данных из
очереди принтера! Конечно, когда разные процессы взаимодействуют, програмист должен
следить за порядком, о чем будет рассказано ниже.
Следующее определение - поток (нить, thread). Концепция потоков появилась,
когда стало ясно, что желательно иметь приложения, осуществляющие набор действий
с наименьшими затратами на переключение, по возможности одновременно. В ситуациях,
когда некие действия могут вызвать существенную задержку в одном из потоков
(например, ожидание ввода от пользователя), часто желательно, чтобы программа
имела возможность осуществлять другие действия независимо (например, фоновую
проверку орфографии или обработку входящих сетевых сообщений). Однако создание
нового процесса для каждого действия (с соответственно возникающей задачей обеспечения
их взаимодействия) часто является неоправданным.
Пример.
Если нужно показать хороший пример многопоточности, то на эту роль прекрасно подходит
Проводник (т.е. Windows Shell). Сделайте двойной щелчок на "My Computer", и откройте
несколько папок, создавая новое окно для каждой. Теперь запустите длительное копирование
в одном из окон. Появляется индикатор копирования, и это окно не отвечает на действия
пользователя. Однако все другие окна можно использовать. Очевидно, что несколько
действий может исполняться одновременно при единственной запущенной копии explorer.exe.
В этом и состоит сущность многопоточности.
Разделение времени.
В большинстве систем, поддерживающих многопоточность, может быть много пользователей,
делающих одновременные запросы к вычислительной системе. Обычно число процессоров
в системе меньше, чем число потоков, которые могут исполняться параллельно. Большинство
систем поддерживает разделение времени (time slicing), известное также
как вытесняющая многозадачность (pre-emptive multitasking) для решения
этой проблемы. В системе с разделением времени потоки запускаются на короткое
время, а затем вытесняются; т.е. таймер периодически заставляет ОС заново решать,
какие потоки должны исполняться, потенциально останавливая уже выполняющиеся потоки,
и запуская другие, которые были приостановлены. Это позволяет даже единственному
процессору выполнять много потоков. На PC эти промежутки времени составляют порядка
55 миллисекунд.
Для чего используют потоки?
Потоки не должны изменять семантику программы. Они просто изменяют время выполнения
операций. В результате они почти всегда используются для изящного решения проблем,
связанных с производительностью. Вот несколько примеров ситуаций, в которых можно
использовать потоки:
- Выполнение длительных действий: когда приложение ведет расчеты, оно не отвечает
на сообщения, в результате не обновляется экран.
- Выполнение фоновых действий: некоторые задачи не критичны ко времени, но
должны выполняться постоянно.
- Выполнение действий по вводу-выводу (I/O): работа с диском или сетью может
привести к неопределенным задержкам. Потоки дадут возможность в таких случаях
не останавливать исполнение других частей программы.
Все эти примеры имеют общее: некоторые действия в программе могут вызвать потенциально
большую задержку в работе CPU, недопустимую для других операций, которые нужно
провести именно сейчас . Конечно, есть и другие преимущества, например:
- При использовании многопроцессорных систем: приложение с единственным потоком
не будет использовать два или более процессоров! В Главе 3 это объяснено более
детально.
- Эффективное разделение времени: используя приоритеты процессов и потоков,
вы обеспечите наиболее правильное использование времени CPU.
Мудрое использование потоков делает медленные, плохо взаимодействующие с пользователем
программы быстрыми и удобными, эффективными, и может значительно улучшить как
производительность, так и удобство использования.
[Содержание]
[Далее]
© Martin Harvey
2000.