1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
| ;----------------------------------------------------------
; synch3.asm - Win32 консольнаz программа для
; изучения средств синхронизации потоков в режиме ядра.
;----------------------------------------------------------
.486
.model flat,STDCALL ; Модель памяти flat
; STDCALL - передача параметров в стиле С (справа-налево),
; вызываемая процедура чистит за собою стек
%NOINCL ; Запретить вывод текста подключаемых файлов
include WindowConA.inc
; Объявления внешними функций Win32 (ASCII), используемых в программе:
extrn AllocConsole:PROC
extrn SetConsoleTitleA:PROC
extrn SetConsoleCursorPosition:PROC
extrn ReadFile:PROC
extrn CloseHandle:PROC
extrn ExitProcess:PROC
extrn MoveFileA:PROC
extrn CreateFileA:PROC
extrn GetStdHandle:PROC
extrn WriteConsoleA:PROC
extrn ReadConsoleA:PROC
extrn WriteFile:PROC
extrn GetLastError:PROC
extrn CreateThread:PROC
extrn ExitProcess:PROC
extrn SwitchToThread:PROC
extrn Sleep:PROC
extrn InitializeCriticalSection:PROC
extrn WaitForSingleObject:PROC
extrn CreateEventA:PROC
extrn SetEvent:PROC
; ---------------------------------------------
; Дополнительно подключаем
extrn CreateMutex:PROC
extrn ReleaseMutex:PROC
; extrn OpenMutex:PROC
; ---------------------------------------------
; Макрокос установки курсора у заданнyю позицию
Set_cursor macro cursor,posx,posy,descr,lbl
mov cursor.xx,posx
push eax
mov ax, posy
mov cursor.yy, ax
pop eax
push cursor
push descr
call SetConsoleCursorPosition
cmp eax, 0
jz lbl ; Если неудачно
endm
; --------------------------------------------------
; Структура для установки положения курсора в консоли:
COORD struc
xx dw 0
yy dw 0
COORD ends
; --------------------------------------------------
; ------------ К исходной программе ----------------
; ------------- добавим структуру ------------------
PSECURITY_ATTRIBUTES struc
nLength dd 5
lpSecurityDescriptor dd NULL
bInheritHandle dd TRUE
PSECURITY_ATTRIBUTES ends
; -------------------------------------
; Сегмент данных
.data
con COORD <>
dummy dd 0 ; Фиктивный аргумент функции потока
pThreadID dd 0
hThread dd 0 ; Дескриптор потока 0
pThreadID1 dd 0
hThread1 dd 0 ; Дескриптор потока 1
hEvent dd 0 ; Дескриптор события
dOut dd 0 ; Дескриптор вывода консоли
dIn dd 0 ; Дескриптор ввода консоли
NumInfo dd 0 ; Переменная вывода "титульной" строки
; ---- Добавим еще переменную ------
hMtx dd 0 ; Описатель мьютекса
; --------------------------------------------------------
; Задаем "титульную" строку для вывода
INFO db " Replacement of Events on Mutex "
LENINFO =$-INFO
; --------------------------------------------------------------
str_out0 db "Client 0: ", 0 ; Строка первого сообщения
len_out0=$-str_out0
str_out1 db "Client 1:", 0 ; Строка второго сообщения
len_out1=$-str_out1
NumWri dd 0
buffer db 20 dup(0) ; Установка буфера
nbuff dd 20
title_text db "Synchronisation test", 0 ; Заголовок консоли
; --------------------------------------------------
; Переменная вывода "титульной" строки - устанавливает номер строки позиции курсора
numrow dw 0
; --------------------------------------------------
.code
; -------------- Объявим мьютекс --------------------
Mtx PSECURITY_ATTRIBUTES <>
; ----------------------------------------------------
start proc ; Точка входа в программу
call AllocConsole ; Запрос консоли
test ax, ax ; Проверить успешность запроса консоли
jz exit ; Если неудачно
; Вывод заголовка консоли
push offset title_text
call SetConsoleTitleA
; ------- Получить стандартный дескриптор вывода ---------------
push STD_OUTPUT_HANDLE
call GetStdHandle
mov dOut, eax ; в dOut-дескриптор вывода консоли
cmp eax, 0
jz exit ; Если неудачно
; ------- Получить стандартный дескриптор ввода ---------------
push STD_INPUT_HANDLE
call GetStdHandle
mov dIn, eax ; в dIn-дескриптор ввода консоли
cmp eax, 0
jz exit ; Если неудачно
; ---------------- Вывод "титульной" строки сообщения -----------------
pusha
Set_cursor con,1,numrow,dOut,exit
inc numrow
push 0
push offset NumInfo ; Количество выводимых на экран символов
push LENINFO ; Длина строки для вывода на экран
push offset INFO ; Адрес строки для вывода на экран
push dOut
call WriteConsoleA
cmp eax, 0
jz exit ; Если неудачно
popa
; ----------------------------------------------------
; ----------- Создание события заменим ---------------
; push NULL
; push TRUE
; push FALSE
; push NULL
; call CreateEventA
; cmp eax, NULL
; je exit ; Если неудачно
; mov hEvent, eax
; --------------------------------------------------------
; ---------------- Создание мьютекса ---------------------
push NULL
push FALSE
push offset Mtx
call CreateMutex
cmp eax, NULL
je exit ; Если неудачно
mov hMtx, eax
; -------------------------------------------------------
; ----------- Создание дочерних потоков ----------------------
push offset pThreadID
push NULL
push offset dummy
push offset ThreadProc
push NULL
push NULL
call CreateThread
cmp eax, NULL
je exit ; Выход, если неудачно
mov hThread, eax
push offset pThreadID1
push NULL
push offset dummy
push offset ThreadProc1
push NULL
push NULL
call CreateThread
cmp eax, NULL
je exit ; Выход, если неудачно
mov hThread1, eax
; ---------- Ожидание завершения работы потока ------------
push 0ffffffffh ; Устанавливаем время ожидания
push hThread
call WaitForSingleObject
push 0ffffffffh ; Устанавливаем время ожидания
push hThread1
call WaitForSingleObject
; ------------ Вывести содержимое буфера ------------------
Set_cursor con,1,5,dOut,exit
push 0
push offset NumWri ; Количество выведенных на экран символов
push nbuff ; Длина строки для вывода на экран
push offset buffer ; Адрес строки для вивода на экран
push dOut
call WriteConsoleA
cmp eax, 0
jz exit ; Если неудачно
; ------------- Обработку события заменяем ------------
; ------- Перевод события в свободное состояние -------
; push hEvent
; call SetEvent
; -----------------------------------------------------
; ------- Перевод мьтеска в свободное состояние -------
push hMtx
; push TRUE
call ReleaseMutex ; Освобождаем мьютекс
; -----------------------------------------------------
; ------- ожидание перевода каретки для выхода -------
push 0
push offset NumWri ; Количество выведенных символов
push len_out0 ; Размер буфера вывода
push offset str_out0 ; Вывод строки первого сообщения
push dIn
call ReadConsoleA
cmp eax, 0
jz exit ; Если неудачно
exit:
; --------- Закрытие описателя дочернего потока --------
push hThread
call CloseHandle
push hThread1
call CloseHandle
; ------------ Выход из программы ----------------------
; подготовка вызова VOID ExitProcess(UINT uExitCode)
push 0
call ExitProcess
start endp
; --------------Процедура потока 0 ---------------------
ThreadProc proc
arg param:DWORD
uses ebx,edi,esi
; ------------ Обработку события заменяем --------------
;---------------- Ожидание события ---------------------
; push 0ffffffffh
; push hEvent
; call WaitForSingleObject
;---------------- Ожидание мьютекса ---------------------
; push 0ffffffffh
push hMtx
; push INFINITE
push 0ffffffffh ; Устанавливаем ожидание
call WaitForSingleObject
; ---------------- Вывести сообщение ----------------------
Set_cursor con,1,1,dOut,exit_proc
push 0
push offset NumWri ; Количество выведенных на экран символов
push len_out0 ; Длина строки для вывода на экран
push offset str_out0 ; Адрес строки для вывода на экран
push dOut
call WriteConsoleA
; -------------------- Ввести строку -----------------------
push 0
push offset NumWri ; Количество введенных символов
push nbuff ; Длина строки для вывода на экран
push offset buffer ; Адрес буфера для введенной строки
push dIn
call ReadConsoleA
cmp eax, 0
jz exit ; Если неудачно
exit_proc: ; Завершить процедуру
; ------------- Обработку события заменяем ------------
; push hEvent
; call SetEvent
push offset hMtx
call ReleaseMutex
; --------------------- Возврат ------------------
ret
ThreadProc endp
; -------------- Процедура потока 1 ------------------------
ThreadProc1 proc
arg param:DWORD
uses ebx,edi,esi
; ------------------ Ожидание события ----------------------
; push 0ffffffffh
; push hEvent
; call WaitForSingleObject
;---------------- Ожидание мьютекса ---------------------
; push 0ffffffffh
push offset hMtx ; Устанавливаем ожидание
; push INFINITE
push 0ffffffffh
call WaitForSingleObject
; ------------------ Вывод сообщения -----------------------
Set_cursor con,1,3,dOut,exit_proc1
push 0
push offset NumWri ; Количество выведенных на экран символов
push len_out1 ; Длина строки для вывода на экран
push offset str_out1 ; Адрес строки для вывода на экран
push dOut
call WriteConsoleA
; ------------------ Ввести строку -------------------------
push 0
push offset NumWri ; Количество введенных символов
push nbuff ; Длина строки для вывода на экран
push offset buffer ; Адрес буфера для введенной строки
push dIn
call ReadConsoleA
cmp eax, 0
jz exit ; Если неудачно
exit_proc1: ; Завершение процедуры
; push hEvent
; call SetEvent
push offset hMtx
call ReleaseMutex
ret
ThreadProc1 endp
end start
; ------------------------ КОНЕЦ ------------------------ |