Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа Потоки.doc
Скачиваний:
9
Добавлен:
19.12.2018
Размер:
178.69 Кб
Скачать

Министерство образования и науки Российской Федерации

Казанский государственный технический университет

имени А.Н. Туполева

____________________________________________

Межкафедральный филиал факультета № 4 в ОАО ICL-КПО ВС

Р.Ф. Миннибаев

Методическое руководство к

лабораторной работе

“ Потоки. Запуск - завершение потоков.

Остановка - возобновление потоков.

Синхронизация потоков с помощью критических секций.”

по дисциплине “Системное программирование”

КАЗАНЬ 2004.

Содержание

1. Потоки. Определение. Области применения 3

2. Необходимость создания потоков 3

3. Функция потока. Создание потока 5

4. Завершение потока 8

5. Возврат управления функцией потока 8

6. Приостановка и возобновление потоков 8

7. Функция Sleep 9

8. Переключение потоков 9

9. Синхронизация потоков 10

9.1. Критические секции 10

9.2. Правила использования критических секций 13

10. Порядок выполнения работы 16

11. Контрольные вопросы 17

1. Потоки. Определение. Области применения

В многопоточной среде программы могут быть разделены на части, называемые потоками выполнения (threads), которые выполняются одновременно. В терминах программы «поток» — это просто функция, которая может также вызывать другие функции программы. Программа начинает выполняться со своего главного (первичного) потока, который в традиционных программах на языке C является функцией main, а в Windows-программах — WinMain. Будучи выполняемой, функция может создавать новые потоки обработки, выполняя системный вызов с указанием функции инициализации потока (initial threading function). Операционная система в вытесняющем режиме переключает управление между потоками подобно тому, как она это делает с процессами.

Процесс фактически состоит из двух компонентов объекта ядра "процесс" и адресного пространства так вот, любой поток также состоит из двух компонентов.

  1. объекта ядра, через который операционная система управляет потоком, там же хранится статистическая информация о потоке;

  2. стека потока, который содержит параметры всех функций и локальные переменные, необходимые потоку для выполнения кода.

Процессы инертны, сам по себе процесс ничего не исполняет, он просто служит контейнером потоков. Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах. На практике это означает, что потоки исполняют код и манипулируют данными в адресном пространстве процесса. Поэтому, если два и более потоков выполняется в контексте одного процесса, все они делят одно адресное пространство. Потоки могут исполнять один и тот же код и манипулировать одними и теми же данными, а также совместно использовать описатели объектов ядра, поскольку таблица описателей создается не в отдельных потоках, а в процессах.

Как видите, процессы используют куда больше системных ресурсов, чем потоки Причина кроется в адресном пространстве. Создание виртуального адресного пространства для процесса требует значительных системных ресурсов. При этом ведется масса всяческой статистики, на что уходит немало памяти. В адресное пространство загружаются EXE- и DLL-файлы, а значит, нужны файловые ресурсы. С другой стороны, потоку требуются лишь соответствующий объект ядра и стек, объем статистических сведений о потоке невелик и много памяти не занимает.

Так как потоки расходуют существенно меньше ресурсов, чем процессы, старайтесь решать свои задачи за счет использования дополнительных потоков и избегайте создания новых процессов. Только не принимайте этот совет за жесткое правило — многие проекты лучше реализовать на основе множества процессов. Нужно просто помнить об издержках и соразмерять цель и средства.

2. Необходимость создания потоков

Поток (thread) определяет последовательность исполнения кода в процессе. При инициализации процесса система всегда создает первичный поток. Начинаясь со стартового кода из библиотеки С/С++, который в свою очередь вызывает входную функцию (WinMain, wWinMain, main или wmain) из программы, он живет до того момента, когда входная функция возвращает управление стартовому коду и тот вызывает функцию ExitProcess. Большинство приложений обходится единственным, первичным потоком. Однако процессы могут создавать дополнительные потоки, что позволяет им эффективнее выполнять свою работу.

У каждого компьютера есть чрезвычайно мощный ресурс — центральный процессор. Чтобы процессор всегда был при деле, его нагружают самыми разнообразными задачами. Вот несколько примеров:

  • Пользователь активизирует службу индексации данных (content indexing service) Windows 2000. Она создает поток с низким приоритетом, который, периодически пробуждаясь, индексирует содержимое файлов на дисковых устройствах компьютера. Чтобы найти какой-либо файл, пользователь открывает окно Search Results (щелкнув кнопку Start и выбрав из меню Search команду For Files Or Folders) и вводит в поле Containing Text нужные критерии поиска. После этого начинается поиск по индексу, и на экране появляется список файлов, удовлетворяющих этим критериям. Служба индексации данных значительно увеличивает скорость поиска, так как при ее использовании больше не требуется открывать, сканировать и закрывать каждый файл на диске.

  • Пользователь запускает программу для дефрагментации дисков, поставляемую с Windows 2000. Благодаря потокам с более низким приоритетом можно пользоваться этой программой в фоновом режиме и дефрагментировать диски в те моменты, когда других дел у системы нет.

  • Нетрудно представить будущую версию компилятора, способную автоматически компилировать файлы исходного кода в паузах, возникающих при наборе текста программы. Тогда предупреждения и сообщения об ошибках появлялись бы практически в режиме реального времени, и разработчики тут же видели бы, в чем ошиблись. Самое интересное, что Microsoft Visual Studio в какой-то мере уже умеет это делать, — обратите внимание на секцию ClassView в Workspace.

  • Электронные таблицы пересчитывают данные в фоновом режиме

  • Текстовые процессоры разбивают текст на страницы, проверяют его на орфографические и грамматические ошибки, а также печатают в фоновом режиме.

  • Файлы можно копировать на другие носители тоже в фоновом режиме.

  • Web-браузеры способны взаимодействовать с серверами в фоновом режиме. Благодаря этому пользователь может перейти на другой Web-узел, не дожидаясь, когда будут получены результаты с текущего Web-узла.

Одна важная вещь, на которую необходимо обратить внимание во всех этих примерах, заключается в том, что поддержка многопоточности позволяет упростить пользовательский интерфейс приложения. Если компилятор ведет сборку программы в те моменты, когда программист делает паузы в наборе ее текста, отпадает необходимость в командах меню Build. То же самое относится к командам Check Spelling и Check Grammar в текстовых процессорах.

В примере с Web-браузером выделение ввода-вывода (сетевого, файлового или какого-то другого) в отдельный поток обеспечивает «отзывчивость» пользовательского интерфейса приложения даже при интенсивной передаче данных. Вообразите приложение, которое сортирует записи в базе данных, печатает документ или копирует файлы. Возложив любую из этих задач, так или иначе связанных с вводом-выводом, на отдельный поток, пользователь может по-прежнему работать с интерфейсом приложения и при необходимости отменить операцию, выполняемую в фоновом режиме.

Многопоточное приложение легче масштабируется. Каждый поток можно закрепить за определенным процессором. Так что, если в компьютере имеется два процессора, а в приложении — два потока, оба процессора будут при деле. Две задачи смогут выполняться одновременно.

Потоки - вещь невероятно полезная, когда ими пользуются правильно. Увы, решая старые проблемы, можно создать себе новые. Допустим, при разработке текстового процессора можно выделить функциональный блок, отвечающий за распечатку, в отдельный поток. Идея вроде неплоха: пользователь, отправив документ на распечатку, может сразу вернуться к редактированию. Тогда информация в документе может быть изменена при распечатке документа. Как видите, теперь встает совершенно новая проблема, с которой прежде сталкиваться не приходилось. Но если разрешить при распечатке редактирование любых документов, кроме того, который печатается в данный момент или скопировать документ во временный файл и отправить на печать именно его, а пользователь в это время редактирует оригинал. Когда распечатка временного файла закончится, он удаляется — вот и все.

Еще одно узкое место, где неправильное применение потоков может привести к появлению проблем, — разработка пользовательского интерфейса в приложении. В подавляющем большинстве программ все компоненты пользовательского интерфейса (окна) обрабатываются одним и тем же потоком. И дочерние окна любого окна определенно должен создавать только один поток. Создание разных окон в разных потоках иногда имеет смысл, но такие случаи действительно редки.

Обычно в приложении существует один поток, отвечающий за поддержку пользовательского интерфейса, — он создает все окна и содержит цикл GetMessage. Любые другие потоки в процессе являются рабочими (т. e. отвечают за вычисления, ввод вывод и другие операции) и не создают никаких окон. Поток пользовательского интерфейса, как правило, имеет более высокий приоритет, чем рабочие потоки, — это нужно для того, чтобы он всегда быстро реагировал на действия пользователя.

Несколько потоков пользовательского интерфейса в одном процессе можно обнаружить в таких приложениях, как Windows Explorer. Он создает отдельный поток для каждого окна папки. Это позволяет копировать файлы из одной папки в другую и попутно просматривать содержимое еще какой-то папки. Кроме того, если какая-то ошибка в Explorer приводит к краху одного из его потоков, прочие потоки остаются работоспособны.

Таким образом, многопоточность следует использовать разумно. Не создавайте несколько потоков только потому, что это возможно. Многие полезные и мощные программы по-прежнему строятся на основе одного первичного потока, принадлежащего процессу.