Главная » Delphi » Внеприоритетный поток

0

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

НА ЗАМЕТКУ

Внеприоритетные потоки допустимы для Windows NT 3.51 SP3 и выше, Windows 2000, Windows XP, Windows 98 и Windows ME.

Внеприоритетные потоки разработаны так,  чтобы  они  выполнялись внутри  кон текста  обычного потока, поэтому  один  обычный поток  может  содержать несколько внеприоритетных. Прежде чем можно  будет использовать внеприоритетные потоки внутри  обычного, его тоже  необходимо преобразовать во внеприоритетный поток  с помощью функции API ConvertThreadToFiber(). Эта функция определена в модуле Windows следующим образом:

function ConvertThreadToFiber(lpParameter:

Pointer): BOOL; stdcall;

Единый параметр  (lone  parameter), lpParameter, типа  Pointer позволяет пере дать  32 битовый указатель  на  данные, специфические для  конкретного внеприори тетного потока. Этот  подход  аналогичен применяемому при  передаче данных  обыч ному потоку с помощью функций BeginThread() и CreateThread(). В модуле Win- dows тип  возвращаемого значения определен неправильно. Там он указан как BOOL,но фактически возвращается указатель на объект внеприоритетного потока. Поэтому, прежде чем использовать возвращаемое значение, необходимо осуществить его при ведение к необходимому типу.

Как  только   поток   будет  преобразован  во  внеприоритетный,  появится возмож ность  создать  другие  внеприоритетные потоки и расписание периодов их выполне ния. Чтобы создать  дополнительный внеприоритетный поток, применяется функция API CreateFiber(), которая определена в модуле Windows следующим образом:

function CreateFiber(dwStackSize: DWORD;

lpStartAddress: TFNFiberStartRoutine;

lpParameter: Pointer): BOOL; stdcall;

Параметр dwStackSize определяет исходный размер (в  байтах) стека  внепри оритетного потока. Нулевое  значение этого  параметра равнозначно требованию ус тановить размер стека,  принятый по умолчанию. Параметр lpStartAddress опреде ляет  адрес  процедуры, которую  внеприоритетный поток  должен  выполнить при  за пуске.    lpParameter определяет   все    32 битовые   данные,   специфические   для внеприоритетного  потока, которые необходимо ему передавать. Тип  значения, воз вращаемого этой  функцией, как и у ConvertThreadToFiber(), указан неправильно. В действительности, возвращается указатель  на созданный объект внеприоритетного потока, и перед  его применением необходимо осуществить приведение типа.

Создав  несколько внеприоритетных потоков, можно  переключаться между ними используя функцию API SwitchToFiber(). Эта функция определена в модуле Win- dows таким образом:

function SwitchToFiber(lpFiber: Pointer): BOOL; stdcall;

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

Когда приходит время  завершать работу внеприоритетного потока, достаточно передать указатель на его объект функции API DeleteFiber():

function DeleteFiber(lpFiber: Pointer): BOOL; stdcall;

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

Вызов функции DeleteFiber() для выполняющегося в настоящий момент внепри- оритетного потока приведет к вызову функции ExitThread(), которая завершает весь поток. Поэтому, если не планируется завершение главного потока, используйте функ-цию DeleteFiber() лишь для ожидающих (приостановленных) внеприоритетных по-

токов.

Четыре вышеописанные функции позволяют выполнить большую часть  действий, необходимых для работы с внеприоритетными  потоками. Кроме  того,  в файлах заго ловков Win32  (Win32  header files)  определены некоторые дополнительные вспомога тельные функции  и  типы,  отсутствующие в Delphi, но  очень  полезные и  удобные. В листинге 5.14 представлен код модуля Fiber, который содержит дополнительные определения, отсутствующие в модуле Windows.

Листинг 5.14. Модуль Fiber.pas

unit Fiber;

interface

uses Windows;

// Определение типов для внеприоритетного потока и процедуры

// start из файла заголовка winbase.h:

type

PFIBER_START_ROUTINE = procedure (lpFiberParameter: Pointer);

stdcall;

LPFIBER_START_ROUTINE = PFIBER_START_ROUTINE; TFiberFunc = PFIBER_START_ROUTINE;

function GetCurrentFiber: Pointer;

function GetFiberData: Pointer;

implementation

// Специфические для процессоров X86 встраиваемые функции

// из файла заголовка winnt.h:

function GetCurrentFiber: Pointer;

asm

mov eax, fs:[$10]

end;

function GetFiberData: Pointer;

asm

mov eax, fs:[$10]

mov eax, [eax]

end;

end.В данном  примере продемонстрировано практическое применение внеприори тетных потоков. Здесь  создается несколько внеприоритетных потоков и осуществля ется  переключение между ними,  что  позволяет одновременно выполнять несколько действий. Основная форма этого приложения представлена на рис. 5.11.

end.Наиболее интересные события этого  примера происходят в функции Thread- Func(), которая является функцией вторичного потока, созданного при  щелчке  на кнопке. Здесь  осуществляется вызов  функции ConvertThreadToFiber(), преобра зующей обычный поток  во внеприоритетный, затем,  несколько раз подряд, происхо дит вызов  функции CreateFiber(), что позволяет создать  три дополнительных вне приоритетных потока. Когда  все внеприоритетные потоки будут подготовлены, вы полняется функция FiberFunc(), которая представляет собой  не  более  чем  беско нечный цикл For, от 0 до бесконечности посылающий сообщения через каждые  100 циклов, чтобы  отобразить очередное значение в надписях формы, и через каждые

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

Приложение использует простую  и надежную  методику  связи  вторичных потоков с основным,  основанную на  передаче сообщений дескриптору окна  Application.Каждому внеприоритетному потоку  присвоен номер  от 1 и 4. По этому номеру  обра ботчик сообщения в основном потоке определяет, какой  именно из  внеприоритет ных потоков послал сообщение.

Рис. 5.12 демонстрируют приложение FibTest в действии. Тот  факт,  что  числа  в надписях формы близки  по значению но не одинаковы, доказывает, что  каждый  из внеприоритетных потоков при выполнении использует свой собственный стек.

Резюме

Рис. 5.12. Проекта FibTest в действии

В этой  главе  рассматривались потоки и правила работы с ними  в среде  Delphi, а также  описывались методы  синхронизации нескольких потоков и поддержки связи между вторичными потоками и  главным  потоком приложения Delphi. Кроме  того, здесь были продемонстрированы примеры использования потоков в контексте ре альных  приложений поиска  файлов и работы с базой  данных  и дано общее  представ ление  о возможности рисования в форме с одновременным использованием несколь ких потоков. И, в заключение, было показано все изящество внеприоритетных пото ков,   которые   позволяют  самостоятельно  управлять  периодами  их   выполнения. В главе  6, “Динамически компонуемые библиотеки”, содержится подробная инфор мация о создании и применении DLL в Delphi.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии