FreeBASIC в России

   

 Главная   Исходники   Русскоязычный форум   Полезные файлы   Пользователи   Поиск

 

 FB Wiki   Уроки   Скачать FreeBASIC   Проекты   Ссылки   Загрузить   Каталог ссылок

 
 

 Замечания и предложения по работе сайта оставляйте здесь.

Сейчас на сайте:

Вы вошли как: Guest   Регистрация   

Логин:     Пароль:     

Создай бесплатно WebMoney кошелёк на своём мобильном всего за 5 минут

 

Делаем dll своими руками

Хэндл окна

Графические средства языка

Точка пересечения отрезков

Окна без рамки

Физика поведения ядра

Win32 API Введение

►Урок 1 Win32 API

►Урок 2 Win32 API

►Урок 3 Win32 API

►Урок 4 Win32 API

►Урок 5 Win32 API

►Урок 6 Win32 API

►Урок 7 Win32 API

►Урок 8 Win32 API

►Урок 9 Win32 API

►Урок 10 Win32 API

►Урок 11 Win32 API

►Урок 12 Win32 API

►Урок 13 Win32 API

►Урок 14 Win32 API

►Урок 15 Win32 API

►Урок 16 Win32 API

►Урок 17 Win32 API

►Урок 18 Win32 API

►Урок 19 Win32 API

►Урок 20 Win32 API

►Урок 21 Win32 API

►Урок 22 Win32 API

►Урок 23 Win32 API

►Урок 24 Win32 API

Ассоциация файлов

Определить OS

Выводит имя компьютера

 

 

 

Win32 API. Урок 15. Треды (ветви).

Опытом поделился и оптимизировал под FreeBASIC:   15.01.2011

 

Реклама:

все новости спорта

 

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

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

Теория:

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

Треды выполняются в том же процессе, поэтому они имеют доступ ко всем ресурсам процесса: глобальным переменным, хэндлам и т.д. Тем не менее, каждый тред имеет свой собственный стек, так что локальные переменные в каждом треде приватны. Каждый тред также имеет свой собственный набор регистров, поэтому когда Windows переключается на другой тред, предыдущий "запоминает" свое состояние и может "восстановить" его, когда он снова получает контроль. Это обеспечивается
внутренними средствами Windows. Мы можем поделить треды на две категории:

1. Тред интерфейса пользователя: тред такого типа создает свое собственное окно, поэтому он получает оконные сообщения. Он может отвечать пользователю с помощью своего окна. Этот тип тредов действует согласно Win16 Mutex правилу, которое позволяет только один тред пользовательского интерфейса в 16-битном пользовательском и gdi-ядре. Пока один подобный тред выполняет код 16-битного пользовательского и gdi-ядра, другие UI треды не могут использовать сервисы этого ядра. Заметьте, что этот Win16 Mutex свойственен Windows 9x, так как его функции обращаются к 16-битному коду. В Windows NT нет Win16 Mutex'а, поэтому треды пользовательского интерфейса под NT работают более плавно, чем под Windows 95.
2. рабочий тред: Этот тип тредов не создает окно, поэтому он не может принимать какие-либо windows-сообщения. Он существует только для того, чтобы делать предназначенную ему работу на заднем фоне (согласно своему названию).

Я советую следующую стратегию при использовании мультитредовых способностей Win32: позвольте основному треду делать все, что связанно с пользовательским интерфейсом, а остальным делать тяжелую работу в фоновом режиме. В этом случае, основной тред - Правитель, другие треды - его помощники. правитель поручает им определенные задания, в то время как сам общается с публикой. Его помощники послушно выполняют работу и докладывают об этом Правителю. Если бы Правитель
делал всю работу сам, он бы не смог уделять достаточно внимания народу или прессе. Это похоже на окно, которое занято продолжительной работой в основном треде: оно не отвечает пользователю, пока работа не будет выполнена. Такая программа может быть улучшена созданием дополнительного треда, который возьмет
часть работы на себя и позволит основной ветви отвечать на команды пользователя.

Мы можем создать тред с помощью вызова функции CreateThread, которая имеет следующий синтаксис:

function CreateThread _
(byval lpThreadAttributes as LPSECURITY_ATTRIBUTES, _
byval dwStackSize as DWORD, _
byval lpStartAddress as LPTHREAD_START_ROUTINE, _
byval lpparameter as PVOID, _
byval dwCreationFlags as DWORD, _
byval lpThreadId as PDWORD) as HANDLE

Функция CreateThread похожа на Createprocess.

• lpThreadAttributes --> Вы можете использовать NULL, если хотите, чтобы у треда были установки безопасности по умолчанию.
• dwStackSize --> укажите размер стека треда. Если вы хотите, чтобы тред имел такой же размер стека, как и у основного, используйте NULL в качестве параметра.
• lрStartAddress --> Адрес функции треда. Эта функция будет выполнять предназначенную для треда работу. Эта функция должна получать один и только один 32-битный
параметр и возвращать 32-битное значение.
• lparameter --> Параметр, который вы хотите передать функции треда.
• dwCreationFlags --> 0 означает, что тред начинает выполняться сразу же после его создания. Для обратного можно использовать флаг CREATE_SUSPEND.
• lpThreadId --> CreateThread поместит сюда ID созданного треда.

Если вызов CreateThread прошел успешно, она возвращает хэндл созданного треда, в противном случае она возвращает NULL.

Функция треда запускается так скоро, как только заканчивается вызов CreateThread, если только вы не указали флаг CREATE_SUSpENDED. В этом случае тред будет заморожен до вызова функции ResumThread.

Когда функция треда возвращается (с помощью инструкции ret) Windows косвенно вызывает ExitThread для функции треда. Вы можете сами вызвать ExitThread, но в этом немного смысла.
Вы можете получить код выхода треда с помощью функции GetExitCodeThread.

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

Теперь давайте рассмотрим методы коммуникации между тредами. Вот три из них:

• Использование глобальных переменных
• Windows-сообщения
• События

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

Вы также можете использовать windows-сообщения, чтобы осуществлять взаимодействие между тредами. Если все треды имеют юзерский интерфейс, то нет проблем:
этот метод может использоваться для двухсторонней коммуникации. Все, что вам нужно сделать - это определить один или более дополнительных windows-сообщений, которые будут использоваться тредами. Вы определяете сообщение, используя значение WM_USER как базовое, например так:

#define WM_MYCUSTOMMSG WM_USER + &h100

Windows не использует сообщения с номером выше WM_USER, поэтому мы можем использовать значение WM_USER и выше для наших собственных сообщений.

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

• Тред с пользовательским интерфейсом ----> глобальная переменная(ные) ----> рабочий тред
• рабочий тред ----> windows-сообщение ----> Тред с пользовательским интерфейсом

Фактически, мы будем использовать этот метод в нашем примере.

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

Пример:

Скопировать данный код в буфер обмена

Как вы можете видеть ThreadProc выполняет подсчет, требующий некоторого времениЗаметьте, что во время этого вы не сможете ничего сделать с главным окном: вы не сможете его двигать, активировать меню и т.д.
Когда вычисление закончится, появится окно с сообщением. После этого окно будет нормально реагировать на ваши команды.
Чтобы избежать подобного неудобства для пользователя, мы должны поместить процедуру вычисления в отдельный рабочий тред и позволить основному треду продолжать
взаимодействие с пользователем. Вы можете видеть, что хотя основное окно отвечает медленнее, чем обычно, оно все же делает это.

файл thread.bas

Скопировать данный код в буфер обмена

файл thread.bi

Скопировать данный код в буфер обмена

файл thread.rc

Скопировать данный код в буфер обмена

Как вы можете видеть ThreadProc выполняет подсчет, требующий некоторого времени, и когда она заканчивает его, она отправляет сообщение WM_FINISH основному окну. WM_FINISH - это наше собственное сообщение, определенное следующим образом:

#define WM_FINISH WM_USER + &h100

Вам не обязательно добавлять к WM_USER 100h, но будет лучше сделать это. Сообщение WM_FINISH имеет значение только в пределах нашей программы. Когда основное окно получает WM_FINISH, она реагирует на это показом окна с сообщением о том, что подсчет закончен.

Вы можете создать несколько тредов, выбрав "Create Thread" несколько раз. В этом примере применяется односторонняя коммуникация, то есть только тред может уведомлять основное окно о чем-либо. Если вы хотите, чтоб основной тред слал команды рабочему, вы должны сделать следующее:

• добавить пункт меню "Kill Thread".
• добавить глобальную переменную, используемую в качестве флага. TRUE = остановить тред, FALSE = продолжить тред.
• Изменить ThreadProc так, чтобы та проверяла в цикле значение флага.

Когда пользователь выберет "Kill Thread", основная программа установит флаг в TRUE. Когда Threadproc видит, что значение флага равно TRUE, она выходит из цикла и возвращается, что заканчивает действие треда.

[C] Iczelion, пер. Aquila.

 

 

Прокомментировать

Ваше имя:  

Ваш e-mail:  

Сообщение:



Введите код: 

 

 

   Спасибо можно сказать, посетив любую ссылку:

 

 

© 2010-2012

DEPOzit (Попов Денис Владимирович)

WebMoney кошелёк: WMID#302963000004

ICQ:279786014 или R549103331586   Z116647355686