Что нового

Мультипоточность

Olim98

Новичок
Сообщения
48
Репутация
2
AutoIt: 3.3.8.0 и новее
Версия: 1.0

Категория: Разное

Описание: Реализация мультипоточности на AutoIt

Код/Пример:
Код:
$hCallback = DllCallbackRegister("thread", "int", "int")
$hCallback2 = DllCallbackRegister("thread2", "int", "int")

Global $var = 50
DllCall("kernel32.dll", "HANDLE", "CreateThread", "LONG_PTR", 0, "DWORD", 0, "LONG_PTR", DllCallbackGetPtr($hCallback), "ptr", 0, "DWORD", 0, "LONG_PTR", 0)
Sleep(100)
DllCall("kernel32.dll", "HANDLE", "CreateThread", "LONG_PTR", 0, "DWORD", 0, "LONG_PTR", DllCallbackGetPtr($hCallback2), "ptr", 0, "DWORD", 0, "LONG_PTR", 0)

MsgBox(4096, "Основной код", $var)

Func thread($dummy)
	Sleep(100)
	MsgBox(4096, "1Отдельный поток", $var)
EndFunc
Func thread2($dummy)
	Sleep(200)
	MsgBox(4096, "2Отдельный поток", $var)
EndFunc

DllCallbackFree($hCallback)
DllCallbackFree($hCallback2)

История версий:
v1
* Первый релиз)

Автор(ы): Olim98
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
;D в аутоит нет многопоточности. Все что вы сможете сделать - это показывать MsgBox
 
Автор
O

Olim98

Новичок
Сообщения
48
Репутация
2
inververs сказал(а):
;D в AutoIt нет многопоточности. Все что вы сможете сделать - это показывать MsgBox
Нативно нет, но с помощью WinAPI теперь есть. а MsgBox лишь для примера.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
:rofl: :rofl:

Код:
Global $a = 0

$hCallback = DllCallbackRegister("thread", "int", "int")
$hCallback2 = DllCallbackRegister("thread2", "int", "int")

Global $var = 50
DllCall("kernel32.dll", "HANDLE", "CreateThread", "LONG_PTR", 0, "DWORD", 0, "LONG_PTR", DllCallbackGetPtr($hCallback), "ptr", 0, "DWORD", 0, "LONG_PTR", 0)
Sleep(100)
DllCall("kernel32.dll", "HANDLE", "CreateThread", "LONG_PTR", 0, "DWORD", 0, "LONG_PTR", DllCallbackGetPtr($hCallback2), "ptr", 0, "DWORD", 0, "LONG_PTR", 0)

MsgBox(4096, "Основной код", $var)

Func thread($dummy)
	While 1
		$a+=1
		Sleep(100)
		ConsoleWrite($a &@CRLF)
	WEnd
EndFunc
Func thread2($dummy)
	While 1
		$a-=1
		Sleep(100)
		ConsoleWrite($a &@CRLF)
	WEnd
EndFunc

DllCallbackFree($hCallback)
DllCallbackFree($hCallback2)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Olim98

Предупреждение За нарушение общих правил (пункт В.2):
Старайтесь избегать “Over quoting” (преувеличенное цитирование) - цитируйте только необходимую часть сообщения, которая наилучшим образом подчеркнёт суть цитируемого.


С уважением, ваш Администратор.
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
http://autoit-script.ru/index.php?topic=2837.msg110356#msg110356

Все это полная ерунда без возможности практического применения.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Olim98
Неоднократно уже обсуждалось!
Autoit не поддерживает многопоточность, точка :-X

P.S: Что за мания создавать бредовую тему в спецразделе :mad:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
На самом деле многопоточность в AutoIt организовать можно, но нужно иметь некоторое представление о машинном выполнении кода. Ну и естественно, каждая подобная задача должна решаться в индивидуальном порядке. Больший интерес может представлять такая структура скрипта, когда функция-поток полностью написана на машинном коде или оформлена в виде DLL. В этом случае остается только продумать грамотную передачу данных между потоком и скриптом. Вот пример функции, которая размывает (blur) исходное изображение, и работает в 8 потоков:

Код:
#Include <GDIPlus.au3>

If StringRegExpReplace(@AutoItVersion, '(?<!\d)(\d)(?!\d)', '0\1') < '03.03.12.00' Then
	MsgBox(16, 'Error', 'Require AutoIt 3.3.12.0 or later.')
EndIf

$sFile = @ScriptDir & '\Birds.png'

_GDIPlus_Startup()
$hBitmap = _GDIPlus_BitmapCreateFromFile($sFile)
$hBlur = _GDIPlus_BitmapCreateBlurBitmap($hBitmap, 5, 1)
_GDIPlus_ImageSaveToFile($hBlur, StringRegExpReplace($sFile, '(\.[^\.]+)', '_Blur\1'))
_GDIPlus_BitmapDispose($hBlur)
_GDIPlus_BitmapDispose($hBitmap)
_GDIPlus_Shutdown()

Func _GDIPlus_BitmapCreateBlurBitmap($hBitmap, $iRadius, $fAccurate = False)

	Local $tData[2], $hThread, $iThread, $tParams, $bProc, $tProc, $pProc, $aSize, $aHeight, $iLength, $hResult, $aResult

	$aSize = DllCall($__g_hGDIPDll, 'uint', 'GdipGetImageDimension', 'handle', $hBitmap, 'float*', 0, 'float*', 0)
	If (@Error) Or ($aSize[0]) Then
		Return 0
	EndIf
	For $i = 2 To 3
		If $iRadius > $aSize[$i] Then
			$iRadius = $aSize[$i]
		EndIf
	Next
	If $iRadius < 1 Then
		Return 0
	EndIf
	$hResult  = _GDIPlus_BitmapCreateFromScan0($aSize[2], $aSize[3], $GDIP_PXF32ARGB)
	$tData[0] = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $aSize[2], $aSize[3], $GDIP_ILMREAD,  $GDIP_PXF32ARGB)
	$tData[1] = _GDIPlus_BitmapLockBits($hResult, 0, 0, $aSize[2], $aSize[3], $GDIP_ILMWRITE, $GDIP_PXF32ARGB)
	If @AutoItX64 Then
		$bProc = Binary('0x48894C24085541574156415548C7C00A0000004883EC0848C704240000000048FFC875EF4883EC28488BAC24A000000048837D000074054831C0EB0748C7C0010000004821C00F855E010000488BAC24A000000048837D080074054831C0EB0748C7C0010000004821C00F8527010000488BAC24A0000000837D180074054831C0EB0748C7C0010000004821C00F85F1000000488BAC24A0000000837D1C0074054831C0EB0748C7C0010000004821C00F85BB000000488BAC24A0000000837D200074054831C0EB0748C7C0010000004821C00F8585000000488BAC24A0000000837D240074054831C0EB0748C7C0010000004821C07553488BAC24A0000000837D280074054831C0EB0748C7C0010000004821C07521488BAC24A0000000837D2C0074054831C0EB0748C7C0010000004821C07502EB0948C7C001000000EB034831C04821C07502EB0948C7C001000000EB034831C04821C07502EB0948C7C001000000EB034831C04821C07502EB0948C7C001000000EB034831C04821C07502EB0948C7C001000000EB034831C04821C07502EB0948C7C001000000EB034831C04821C07502EB0948C7C001000000EB034831C04821C0740B4831C04863C0E946030000488BAC24A00000004863451450584889442428488BAC24A00000004C637D14488BAC24A00000004863451C4901C749FFCF4C3B7C24280F8CFB020000488BAC24A00000004863451050584889442430488BAC24A00000004C637D10488BAC24A0000000486345184901C749FFCF4C3B7C24300F8CB402000048C74424380000000048C74424400000000048C74424480000000048C74424500000000048C7442458000000004C8B7C2428488BAC24A0000000486345284929C74C897C24604C8B7C24604C8B742428488BAC24A0000000486345284901C64D39F70F8F840100004C8B7C2430488BAC24A0000000486345284929C74C897C24684C8B7C24684C8B742430488BAC24A0000000486345284901C64D39F70F8F2B0100004C8B7C24684D21FF7C614C8B7C2468488BAC24A0000000486345204939C77D3A4C8B7C24604D21FF7C1F4C8B7C2460488BAC24A0000000486345244939C77D0948C7C001000000EB034831C04821C0740948C7C001000000EB034831C04821C0740948C7C001000000EB034831C04821C00F8496000000488BAC24A00000004C8B7D004C8B7424684C8B6C2460488BAC24A0000000486345204C0FAFE84D01EE49C1E6024D01F74C897C24704C8B7C2438488B6C2470480FB645034901C74C897C24384C8B7C2440488B6C2470480FB645024901C74C897C24404C8B7C2448488B6C2470480FB645014901C74C897C24484C8B7C2450488B6C2470480FB645004901C74C897C245048FF4424584C8B7C2468488BAC24A00000004863452C4901C74C897C2468E9B3FEFFFF4C8B7C2460488BAC24A00000004863452C4901C74C897C2460E95AFEFFFF488BAC24A00000004C8B7D084C8B7424304C8B6C2428488BAC24A0000000486345204C0FAFE84D01EE49C1E6024D01F74C897C24704C8B7C2438FF7424584C89F859489948F7F94989C74C89F850488B6C2478588845034C8B7C2440FF7424584C89F859489948F7F94989C74C89F850488B6C2478588845024C8B7C2448FF7424584C89F859489948F7F94989C74C89F850488B6C2478588845014C8B7C2450FF7424584C89F859489948F7F94989C74C89F850488B6C24785888450048FF4424300F8123FDFFFF48FF4424280F81DCFCFFFF48C7C0010000004863C0EB034831C04883C478415D415E415F5DC3')
	Else
		$bProc = Binary('0x55535756BA0A00000083EC04C70424000000004A75F38B6C243C837D0000740431C0EB05B80100000021C00F85090100008B6C243C837D0400740431C0EB05B80100000021C00F85DF0000008B6C243C837D1000740431C0EB05B80100000021C00F85B50000008B6C243C837D1400740431C0EB05B80100000021C00F858B0000008B6C243C837D1800740431C0EB05B80100000021C075658B6C243C837D1C00740431C0EB05B80100000021C0753F8B6C243C837D2000740431C0EB05B80100000021C075198B6C243C837D2400740431C0EB05B80100000021C07502EB07B801000000EB0231C021C07502EB07B801000000EB0231C021C07502EB07B801000000EB0231C021C07502EB07B801000000EB0231C021C07502EB07B801000000EB0231C021C07502EB07B801000000EB0231C021C07502EB07B801000000EB0231C021C0740731C0E9400200008B6C243C8B450C8904248B6C243C8B5D0C8B6C243C035D144B3B1C240F8C150200008B6C243C8B4508894424048B6C243C8B5D088B6C243C035D104B3B5C24040F8CE8010000C744240800000000C744240C00000000C744241000000000C744241400000000C7442418000000008B1C248B6C243C2B5D20895C241C8B5C241C8B3C248B6C243C037D2039FB0F8F0D0100008B5C24048B6C243C2B5D20895C24208B5C24208B7C24048B6C243C037D2039FB0F8FD30000008B5C242021DB7C438B5C24208B6C243C3B5D187D298B5C241C21DB7C148B5C241C8B6C243C3B5D1C7D07B801000000EB0231C021C07407B801000000EB0231C021C07407B801000000EB0231C021C0746E8B6C243C8B5D008B7C24208B74241C8B6C243C0FAF751801F7C1E70201FB895C24248B5C24088B6C24240FB6450301C3895C24088B5C240C8B6C24240FB6450201C3895C240C8B5C24108B6C24240FB6450101C3895C24108B5C24148B6C24240FB6450001C3895C2414FF4424188B5C24208B6C243C035D24895C2420E916FFFFFF8B5C241C8B6C243C035D24895C241CE9DDFEFFFF8B6C243C8B5D048B7C24048B34248B6C243C0FAF751801F7C1E70201FB895C24248B5C2408FF74241889D85999F7F989C3538B6C2428588845038B5C240CFF74241889D85999F7F989C3538B6C2428588845028B5C2410FF74241889D85999F7F989C3538B6C2428588845018B5C2414FF74241889D85999F7F989C3538B6C242858884500FF4424040F81FFFDFFFFFF04240F81D3FDFFFFB801000000EB0231C083C4285E5F5B5DC20400')
	EndIf
	$iLength = BinaryLen($bProc)
	$pProc = DllCall('kernel32.dll', 'ptr', 'VirtualAlloc', 'ptr', 0, 'ulong_ptr', $iLength, 'dword', 0x1000, 'dword', 0x0040)
	$tProc = DllStructCreate('byte[' & $iLength & ']', $pProc[0])
	DllStructSetData($tProc, 1, $bProc)
	$iThread = 8
	If $iThread > $aSize[3] Then
		$iThread = $aSize[3]
	EndIf
	Dim $aHeight[$iThread]
	Dim $tParams[$iThread]
	Dim $hThread[$iThread]
	If $iThread = 1 Then
		$aHeight[0] = $aSize[3]
	Else
		$aHeight[0] = Floor($aSize[3] / $iThread)
		$aHeight[$iThread - 1] = $aSize[3] - $aHeight[0] * ($iThread - 1)
		For $i = 1 To $iThread - 2
			$aHeight[$i] = $aHeight[0]
		Next
	EndIf
	$iLength = 0
	For $i = 0 To $iThread - 1
		$tParams[$i] = DllStructCreate('ptr;ptr;uint;uint;uint;uint;uint;uint;uint;uint')
		DllStructSetData($tParams[$i], 1, $tData[0].Scan0)
		DllStructSetData($tParams[$i], 2, $tData[1].Scan0)
		DllStructSetData($tParams[$i], 3, 0)
		DllStructSetData($tParams[$i], 4, $iLength)
		DllStructSetData($tParams[$i], 5, $aSize[2])
		DllStructSetData($tParams[$i], 6, $aHeight[$i])
		DllStructSetData($tParams[$i], 7, $aSize[2])
		DllStructSetData($tParams[$i], 8, $aSize[3])
		DllStructSetData($tParams[$i], 9, $iRadius)
		If $fAccurate Then
			DllStructSetData($tParams[$i],10, 1)
		Else
			DllStructSetData($tParams[$i],10, 2)
		EndIf
		$iLength+= $aHeight[$i]
		$aResult = DllCall('kernel32.dll', 'handle', 'CreateThread', 'ptr', 0, 'dword_ptr', 0, 'ptr', $pProc[0], 'struct*', $tParams[$i], 'dword', 0, 'ptr', 0)
		If (Not @Error) And ($aResult[0]) Then
			$hThread[$i] = $aResult[0]
		Else
			$hThread[$i] = 0
		EndIf
	Next
	While 1
		$iLength = 0
		For $i = 0 To $iThread - 1
			If $hThread[$i] Then
				$aResult = DllCall('kernel32.dll', 'bool', 'GetExitCodeThread', 'handle', $hThread[$i], 'dword*', 0)
				If (@Error) Or (Not $aResult[0]) Or ($aResult[2] <> 259) Then
					DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $hThread[$i])
					$hThread[$i] = 0
				Else
					$iLength += 1
				EndIf
			EndIf
		Next
		If Not $iLength Then
			ExitLoop
		EndIf
	WEnd
	$aResult = DllCall('kernel32.dll', 'int', 'VirtualFree', 'ptr', $pProc[0], 'ulong_ptr', 0, 'dword', 0x4000)
	If (@Error) Or (Not $aResult[0]) Then
		; Nothing
	EndIf
	_GDIPlus_BitmapUnlockBits($hResult, $tData[1])
	_GDIPlus_BitmapUnlockBits($hBitmap, $tData[0])
	Return $hResult
EndFunc   ;==>_GDIPlus_BitmapCreateBlurBitmap


А вот сама функция-поток:

Код:
Structure Param
	*Bits1
	*Bits2
	Xt.l
	Yt.l
	Wt.l
	Ht.l
	W.l
	H.l
	L.l
	S.l
EndStructure

Structure ARGB
	B.a
	G.a
	R.a
	A.a
EndStructure

ProcedureDLL.l First(*Param.Param)
	If (Not *Param\Bits1) Or (Not *Param\Bits2) Or (Not *Param\Wt) Or (Not *Param\Ht) Or (Not *Param\W) Or (Not *Param\H) Or (Not *Param\L) Or (Not *Param\S)
		ProcedureReturn 0
	EndIf
	For Yi = *Param\Yt To *Param\Yt + *Param\Ht - 1
		For Xi = *Param\Xt To *Param\Xt + *Param\Wt - 1
			A = 0
			R = 0
			G = 0
			B = 0
			C = 0
			Yj = Yi - *Param\L
			While Yj <= Yi + *Param\L
				Xj = Xi - *Param\L
				While Xj <= Xi + *Param\L
					If (Xj >= 0) And (Xj < *Param\W) And (Yj >= 0) And (Yj < *Param\H)
						*ARGB.ARGB = *Param\Bits1 + (Xj + Yj * *Param\W) * 4
						A = A + *ARGB\A
						R = R + *ARGB\R
						G = G + *ARGB\G
						B = B + *ARGB\B
						C = C + 1
					EndIf
					Xj = Xj + *Param\S
				Wend
				Yj = Yj + *Param\S
			Wend
			*ARGB.ARGB = *Param\Bits2 + (Xi + Yi * *Param\W) * 4
			*ARGB\A = A / C
			*ARGB\R = R / C
			*ARGB\G = G / C
			*ARGB\B = B / C
		Next
	Next
	ProcedureReturn 1
EndProcedure

ProcedureDLL Last()
EndProcedure

Вот еще один пример использования потоков в AutoIt. Но все это реализовано с привлечением компилируемых ЯП, в данном случае PB 4.50.

P.S

Поток, написанный на AutoIt через DllCallback..., работать не будет.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied,
Огромное спасибо за функцию 'GetExitCodeThread'!!!
Я, наконец, понял, как надо в AutoIt отслеживать работу и возвращать результаты из потоков, созданных в Dll на PureBasic.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles, обмен данными проще всего организовать через структуру, а вот синхронизацию, чтобы поток и скрипт не писали данные в структуру одновременно можно несколькими способами. Можно, конечно, намутить что-то с mutex или semaphore, но, IMHO, проще завести флаг, который поток и основной скрипт будут проверять каждый раз перед записью данных в структуру.

Код:
Global $tData = DllStructCreate('bool Busy;...')

...

While $tData.Busy
	; Nothing
WEnd
$tData.Busy = 1
; Запись необходимых данных в структуру $tData
$tData.Busy = 0


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

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied,
Я раньше так и делал, но, ИМХО, через GetExitCodeThread проще и плюс возвращается результат.

OffTopic:
PS
Почему функция, возвращающая handle потока в PureBasic называется ThreadID()? :shok: Не понимаю.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
madmasles сказал(а):
Почему функция, возвращающая handle потока в PureBasic называется ThreadID()? :shok: Не понимаю.[/off]
Потому что это PureBasic, там все через...
 

Prog

Продвинутый
Сообщения
537
Репутация
65
Yashied [?]
а вот синхронизацию, чтобы поток и скрипт не писали данные в структуру одновременно можно несколькими способами. Можно, конечно, намутить что-то с mutex или semaphore, но, IMHO, проще завести флаг, который поток и основной скрипт будут проверять каждый раз перед записью данных в структуру.
Это неправильный подход. Потоки работают асинхронно и возможна такая ситуация что несколько потоков одновременно проверили флаг и на момент проверки он был сброшен. И они все разом начали писать в структуру. Думаю ясно к чему это приведет?
Правильнее использовать Mutex для предотвращения одновременного доступа к данным. А сигнализировать можно как флагом так и семафором.


madmasles [?]
Почему функция, возвращающая handle потока в PureBasic называется ThreadID()?
Потому что хендл это идентификатор (т. е. ID).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Prog сказал(а):
Потоки работают асинхронно и возможна такая ситуация что несколько потоков одновременно проверили флаг и на момент проверки он был сброшен.
В данном контексте речь шла о синхронизации двух потоков. В любом случае можно для каждой пары создать свой флаг, т.к. в большинстве случаев каждый поток выполняет свою задачу. Например, каждый поток копирует свой файл или обрабатывает свою область данных. Если же 100500 потоков лезут в одни и те же данные, то да, здесь предпочтительнее использовать mutex'ы.

Prog сказал(а):
Потому что хендл это идентификатор (т. е. ID).
И ведь не поспоришь. С другой стороны, если говорить о WinAPI (а мы обсуждаем именно его), Handle и ID имеют совершенно разный смысл. Handle - индекс в системной таблице, которая содержит адрес структуры (32/64-бит), а ID - просто число. Хотя, есть и исключения.

P.S

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

qqww22

Новичок
Сообщения
115
Репутация
4
Yashied сказал(а):
И если честно, то я не видел ни одного более-менее серьезного проекта, написанного на PB.
http://www.youtube.com/watch?v=iLvQWIrX6rA

Если и сравнивать пб то с си подобными и делфями.

На мой взгляд его плюсы
+ Низкий порог входа
+ Платформенность
+ Хорошая Скорость
+ Меньше траблов с антивирусами. на Си подобные даже на стандартные функции идут срабатывания в виде Малавара.
+ ОДНАКО есть справка :smile:))

По теме
Можно реализовать многопоточность через dll путём передачи бинарного кода Autoit с запуском в потоке.

ЗЫ если бы написали транслятор кода Autoit под Fasm pb,для меня это был бы шедевр.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Писать 3D на PB, это тоже самое, что делать базы данных на Ассемблере. Поддержка 3D в PB, это одно большое недоразумение, или же реализовано исключительно для оправдания того, что за ЯП требуют денег. Я могу привести сотню программ на AutoIt (в том числе и платные), которые действительно являются полезными, и которыми пользуются довольно много людей. На некоторые программы делались даже обзоры в популярных компьютерных журналах. PB, аууу...



 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
qqww22 сказал(а):
+ Платформенность
Да что же вы прилипли к этой платформенности? Это больше зло, т.к. у ЯП начинает страдать логика. Лучше бы для каждой платформы была своя модификация PB.
 
Верх