Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
System programming / Конспект лекций / Лекция 10 Многозадачность.doc
Скачиваний:
53
Добавлен:
08.05.2015
Размер:
62.46 Кб
Скачать

Многопоточность

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

Программная реализация многозадачности

Когда пользователь запускает программу, Windows создает в памяти компьютера экземпляр программы, называемый процессом. Процесс не является точной копией *.ехе – файла, как это было, например в операционной системе ДОС. Процесс содержит в себе копию *.ехе – файла, а также некоторую другую информацию о функционировании данного приложения. В этой дополнительной информации хранятся, например, границы выделенной приложению памяти, что помогает аппаратно отслеживать корректности обращения к оперативной памяти со стороны приложения. Так как Windows поддерживает механизм виртуальной памяти, то среди этой информации находятся сведения о расположении сегментов программы. Здесь же содержится командная строка, формируемая при запуске программы.

Запустить процесс можно как при помощи командной строки системного меню Windows, при помощи программы Проводника, так и программно, из другого приложения. Это можно выполнить при помощи функций API:

Для 16-битных приложений используется функция WinExec:

UINT WinExec(

LPCSTR lpCmdLine, // command line

UINT uCmdShow// window style

);

Первый параметр является командной строкой, в которой указывается имя файла и параметры, указываемые после имени загружаемого файла.

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

В среде Windows 32 следует использовать другой способ порождения процессов:

BOOL CreateProcess(

LPCTSTR lpApplicationName, // pointer to name of executable module

LPTSTR lpCommandLine, // pointer to command line string

LPSECURITY_ATTRIBUTES lpProcessAttributes, // pointer to process security attributes

LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to thread security attributes

BOOL bInheritHandles, // handle inheritance flag

DWORD dwCreationFlags, // creation flags

LPVOID lpEnvironment, // pointer to new environment block

LPCTSTR lpCurrentDirectory, // pointer to current directory name

LPSTARTUPINFO lpStartupInfo, // pointer to STARTUPINFO

LPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_INFORMATION

);

Первый параметр является указателем на имя запускаемого файла. Имя может содержать полный путь к файлу (диск:\каталог\…\файл). Если имя не содержит пути, то операционная система ищет файл в текущем каталоге, затем в системных каталогах и в каталогах, указанных в разделе PATH при загрузке системы.

Второй параметр указывает на командную строку.

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

bInheritHandles и dwCreationFlags содержит дополнительные флаги управления созданием и приоритетом процесса.

lpEnvironment содержит указатель на буфер памяти, в котором будет создаваться служебная информация по процессу. Если равен NULL, то операционная система сама отводит место в памяти под эту информацию.

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

lpStartupInfo определяет структуру STARTUPINFO , которая описывает окно, создаваемое для запускаемого процесса (в ней содержится информация, похожая на ту, которая передается в процедуру CreateWindow).

lpProcessInformation указатель на структуру, заполняемую после создания нового процесса. Структура содержит информацию о созданном процессе.

Многопоточность в программе реализовать можно несколькими путями.

  1. Непосредственное использование системного таймера для указание процедуры, вызываемой периодически. Данный способ был рассмотрен в лекции "Использование Таймера". Это типичный представитель вытесняющей многозадачности. К достоинствам этого способа можно отнести то, что программа может устанавливать и изменять период вызова функции.

  2. Использование системного таймера для организации посылки синхронных сообщений выбранному окну (порядок организации описан в лекции "Использование Таймера"). С помощью данного способа реализуется невытесняющая многозадачность. Достоинство – изменяемая периодичность посылки сообщений. Недостаток – природа синхронных сообщений не гарантирует четкое выполнение периода прихода сообщений от таймера.

  3. Создание потоков. Данный способ подразумевает определение некоторой процедуры потока, которая запускается параллельно основному процессу приложения. Момент окончания выполнения потока контролирует сама поточная процедура.

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread1,&params,0,&iThread);

Первый параметр определяет атрибуты безопасности для запускаемого потока. Если он равен NULL, то данный поток не может использоваться дочерними процессами.

Второй параметр определяет начальный адрес потока (фактически - имя процедуры потока), например:

DWORD WINAPI Thread1(PVOID pvoid)

{

// Текст потока

}

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

Четвертый параметр определяет дополнительные флаги создания потока. Если этот параметр равен нулю, то поток создастся немедленно.

Последний параметр является адресом переменной, в которую возвращается идентификатор потока.

Использование функции Sleep

Итак, поток – это часть программы, запускаемая параллельно другим задачам процесса. Поток сам определяет как долго ему находится в памяти и какие действия надо совершать. Если поток должен периодически совершать одни и те же действия (например, обновлять экран или проверять почту), то самым естественным способом сделать это является организация бесконечного цикла (подобного циклу обработки сообщений). Однако, в этом случае не определено время цикличности, т.к. временные периоды выполнения потока определены операционной системой. Кроме того, как только одна итерация цикла заканчивается, начинается другая. Как же вызвать приостановку выполнения потока? Для этих целей существует функция Sleep, которая в качестве единственного параметра имеет время, задаваемое в миллисекундах. Функция не осуществляет возврата до тех пор, пока не истечет указанное время. При этом другие потоки и процессы работают в обычных режимах. Если параметр этой функции равен нулю, то операционная система просто лишает текущий поток оставшегося кванта времени.

Следует отметить, что данная функция не освобождает полностью процессор от исполнения потока. Действительно, процессор периодически должен проверять истекло ли время, заданное в функции. То есть, речь идет не о приостановке периодического выполнения потока, а лишь о задержке выполнения алгоритма потока на одной его команде (Sleep).