Четверг, 17.07.2025, 23:20 Приветствую Вас Гость

On-line: Книги, учебники, статьи

Главная | Регистрация | Вход | RSS

Глава 2. Многозадачное программирование(2)

Трансляция программы PROCES.ASM на Рис. 3.2.1.
Пакет MASM32.

 ML /c /coff /DMASM proces.asm
 RC proces.rc
 LINK /SUBSYSTEM:WINDOWS proces.obj proces.res
Пакет TASM32.
 TASM32 /ml proces.asm
 BRCC32 proces.rc
 TLINK32 -aa proces.obj,,,,,proces.res

Думаю, что другой комментарий для программы на Рис. 3.2.1 не требуется.


40 В английской терминологии поток называется "THREAD", что буквально переводится как нить.


II

Теперь пришла пора вплотную заняться потоками. Вначале я намерен решить задачу из предыдущей главы (Рис. 3.1.2) при помощи потока.

Поток может быть создан при помощи функции CreateThread. Рассмотрим параметры этой функции.

  • 1-й параметр. Указатель на структуру атрибутов доступа. Имеет значение только для Windows NT. Обычно полагается NULL.
  • 2-й параметр. Размер стека потока. Если параметр равен нулю, то берется размер стека по умолчанию, равный размеру стека родительского потока.
  • 3-й параметр. Указатель на потоковую функцию, с вызова которой начинается исполнение потока.
  • 4-й параметр. Параметр для потоковой функции.
  • 5-й параметр. Флаг, определяющий состояние потока. Если флаг равен 0, то выполнение потока начинается немедленно. Если значение флага потока равно CREATE_SUSPENDED (4H), то поток находится в состояние ожидания и запускается по выполнению функции ResumeThread.
  • 6-й параметр. Указатель на переменную, куда будет помещен дескриптор потока.

Как уже было сказано, выполнение потока начинается с потоковой функции. Окончание работы этой функции приводит к естественному окончанию работы потока. Поток также может закончить свою работу, выполнив функцию ExitThread с указанием кода выхода. Наконец, порождающий поток может закончить работу порожденного потока при помощи функции TerminateThread. В нашем примере на Рис. 3.2.2 запускаемый процесс не может сам закончить свою работу и прекращает свою работу вместе с приложением по команде TerminateThread. Надо сказать, что такое завершение, вообще говоря, является аварийным и не рекомендуется к обычному употреблению. Связано это с тем, что при таком завершении не выполняется никаких действий по освобождению занятых ресурсов (блоки памяти, открытые файлы и т.п.). Поэтому стройте свои приложения так, что бы поток завершался по выходу из потоковой процедуры. Таким образом, в некотором смысле приведенный ниже пример является демонстрацией того, чего не рекомендуется делать.

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

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

// файл thread.rc
// определение констант
#define WS_SYSMENU 0x00080000L
// элементы на окне должны быть изначально видимы
#define WS_VISIBLE 0x10000000L
// бордюр вокруг элемента
#define WS_BORDER 0x00800000L
// при помощи TAB можно по очереди активизировать элементы
#define WS_TABSTOP 0x00010000L
// текст в окне редактирования прижат к левому краю
#define ES_LEFT 0x000OL
// стиль всех элементов на окне
#define WS_CHILD 0x40000000L
// запрещается ввод с клавиатуры
#define ES_READONLY 0x0800L
// стиль - кнопка
#define BS_PUSHBUTTON 0x00000000L
// центрировать текст на кнопке
#define BS_CENTER 0x00000300L

#define DS_3DLOOK 0x0004L

// определение диалогового окна
DIAL1 DIALOG 0, 0, 240, 100
STYLE WS_SYSMENU | DS_3DLOOK
CAPTION "Пример использования потока"
FONT 8, "Arial"
{
 // окно редактирования, идентификатор 1
 CONTROL "", 1, "edit", ES_LEFT | WS_CHILD
 | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_READONLY,
 100, 5, 130, 12
 // кнопка, идентификатор 2
 CONTROL "Выход", 2, "button", BS_PUSHBUTTON
 | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
 180, 76, 50, 14
}

; файл thread.inc
; константы
; сообщение приходит при закрытии окна
WM_CLOSE equ 10h
; сообщение приходит при создании окна
WM_INITDIALOG equ 110h
; сообщение приходит при событии с элементом на окне
WM_COMMAND equ 111h
; сообщение посылки текста элементу
WM_SETTEXT equ 0Ch

; прототипы внешних процедур
IFDEF MASM
; для MASM
 EXTERN SendMessageA@16:NEAR
 EXTERN GetDlgItem@8:NEAR
 EXTERN Sleep@4:NEAR
 EXTERN TerminateThread@8:NEAR
 EXTERN CreateThread@24:NEAR
 EXTERN wsprintfA:NEAR
 EXTERN GetLocalTime@4:NEAR
 EXTERN ExitProcess@4:NEAR
 EXTERN GetModuleHandleA@4:NEAR
 EXTERN DialogBoxParamA@20:NEAR
 EXTERN EndDialog@8:NEAR
ELSE
; для TASM
 EXTERN SendMessageA:NEAR
 EXTERN GetDlgItem:NEAR
 EXTERN Sleep:NEAR
 EXTERN TerminateThread:NEAR
 EXTERN CreateThread:NEAR
 EXTERN _wsprintfA:NEAR
 EXTERN GetLocalTime:NEAR
 EXTERN ExitProcess:NEAR
 EXTERN GetModuleHandleA:NEAR
 EXTERN DialogBoxParamA:NEAR
 EXTERN EndDialog:NEAR
 SendMessageA@16 = SendMessageA
 GetDlgItem@8 = GetDlgItem
 Sleep@4 = Sleep
 TerminateThread@8 = TerminateThread
 CreateThread@24 = CreateThread
 wsprintfA = _wsprintfA
 GetLocalTime@4 = GetLocalTime
 ExitProcess@4 = ExitProcess
 GetModuleHandleA@4 = GetModuleHandleA
 DialogBoxParamA@20 = DialogBoxParamA
 EndDialog@8 = EndDialog
ENDIF
; структуры
; структура сообщения
MSGSTRUCT STRUC
 MSHWND DD ?
 MSMESSAGE DD ?
 MSWPARAM DD ?
 MSLPARAM DD ?
 MSTIME DD ?
 MSPT DD ?
MSGSTRUCT ENDS

; структура данных дата-время
DAT STRUC
 year DW ?
 month DW ?
 dayweek DW ?
 day DW ?
 hour DW ?
 min DW ?
 sec DW ?
 msec DW ?
DAT ENDS


; файл thread.asm
.386P
; плоская модель
.MODEL FLAT, stdcall
include thread.inc
; директивы компоновщику для подключения библиотек
IFDEF MASM
; для компоновщика LINK.EXE
 includelib c:\masm32\lib\user32.lib
 includelib c:\masm32\lib\kernel32.lib
 includelib c:\masm32\lib\gdi32.lib
ELSE
; для компоновщика TLINK32.EXE
 includelib c:\tasm32\lib\import32.lib
ENDIF
;----------------------------------------------------

; сегмент данных
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
 MSG MSGSTRUCT <?>
 HINST DD 0 ; дескриптор приложения
 PA DB "DIAL1",0
 TIM DB "Дата %u/%u/%u Время %u:%u:%u",0
 STRCOPY DB 50 DUP (?)
 DATA DAT <0>
 HTHR DD ?
_DATA ENDS

; сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:
; получить дескриптор приложения
 PUSH 0
 CALL GetModuleHandleA@4
 MOV [HINST], EAX
; создать диалоговое окно
 PUSH 0
 PUSH OFFSET WNDPROC
 PUSH 0
 PUSH OFFSET PA
 PUSH [HINST]
 CALL DialogBoxParamA@20
 CMP EAX,-1
 JNE KOL
; сообщение об ошибке
KOL:
;------------------------------------
 PUSH 0
 CALL ExitProcess@4
;------------------------------------

; процедура окна
; расположение параметров в стеке
; [EBP+014Н] ; LPARAM
; [EBP+10Н] ; WAPARAM
; [EBP+0CH] ; MES
; [EBP+8] ; HWND
WNDPROC PROC
 PUSH EBP
 MOV EBP,ESP
 PUSH EBX
 PUSH ESI
 PUSH EDI
;-------------------
 CMP DWORD PTR [EBP+0CH],WM_CLOSE
 JNE L1
L3:
; здесь реакция на закрытие окна
; удалить поток
 PUSH 0
 PUSH HTHR
 CALL TerminateThread@8
; закрыть диалог
 PUSH 0
 PUSH DWORD PTR [EBP+08H]
 CALL EndDialog@8
 JMP FINISH
L1:
 CMP DWORD PTR [EBP+0CH],WM_INITDIALOG
 JNE L2
; здесь начальная инициализация
; получить дескриптор окна редактирования
 PUSH 1
 PUSH DWORD PTR [EBP+08H]
 CALL GetDlgItem@8
; создать поток
 PUSH OFFSET HTHR ; сюда дескриптор потока
 PUSH 0
 PUSH EAX ; параметр
 PUSH OFFSET GETTIME ; адрес процедуры
 PUSH 0
 PUSH 0
 CALL CreateThread@24
 JMP FINISH
L2:
 CMP DWORD PTR [EBP+0CH],WM_COMMAND
 JNE FINISH
; кнопка выхода?
 CMP WORD PTR [EBP+10H],2
 JE L3
FINISH:
 POP EDI
 POP ESI
 POP EBX
 POP EBP
 MOV EAX,0
 RET 16
WNDPROC ENDP

; потоковая функция
; [EBP+8] параметр=дескриптор окна редактирования
GETTIME PROC
 PUSH EBP
 MOV EBP,ESP
L0:
; задержка в 1 секунду
 PUSH 1000
 CALL Sleep@4
; получить локальное время
 PUSH OFFSET DATA
 CALL GetLocalTime@4
; получить строку для вывода даты и времени
 MOVZX EAX,DATA.sec
 PUSH EAX
 MOVZX EAX,DATA.min
 PUSH EAX
 MOVZX EAX,DATA.hour
 PUSH EAX
 MOVZX EAX,DATA.year
 PUSH EAX
 MOVZX EAX,DATA.month
 PUSH EAX
 MOVZX EAX,DATA.day
 PUSH EAX
 PUSH OFFSET TIM
 PUSH OFFSET STRCOPY
 CALL wsprintfA
; отправить строку в окно редактирования
 PUSH OFFSET STRCOPY
 PUSH 0
 PUSH WM_SETTEXT
 PUSH DWORD PTR [EBP+08H]
 CALL SendMessageA@16
 JMP L0 ; бесконечный цикл
 POP EBP
 RET 4
GETTIME ENDP
_TEXT ENDS
END STAR

Рис. 3.2.2. Пример создания потока.

Комментарий к программе на Рис. 3.2.2.

Трансляция программы THREAD.ASM на Рис. 3.2.2.
Пакет MASM32.

 ML /c /coff /DMASM thread.asm
 RC thread.rc
 LINK /SUBSYSTEM:WINDOWS thread.obj thread.res
Пакет TASM32.
 TASM32 /ml thread.asm
 BRCC32 thread.rc
 TLINK32 -aa thread.obj,,,,,thread.res

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



Вход на сайт
Поиск
Календарь
«  Июль 2025  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей
Наш опрос
Как Вам удобнее??
Всего ответов: 341
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0