Что нового

Работа с DLL: Как отправить в DLL-файл (фукцию) значение и вернуть обратно?

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Kalisnik [?]
А вот многоядерность как-то снова стороной. Загрузка CPU на исполняемом файле PureBasic 25%.
если создать четыре потока, каждый из которых способен полностью загрузить ядро, получишь 100%.
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Kaster [?]
если создать четыре потока, каждый из которых способен полностью загрузить ядро, получишь 100%.

Т.е. в самом принципе, один поток может работать только с одним ядром? И любое приложение с поддержкой многоядерных систем работает именно по этому же принципу?
 

asdf8

Скриптер
Сообщения
564
Репутация
152
[?]
Цитата сказал(а):
Но размер исполняемого файла...

Слегка обманчивое впечатление, если пользоваться только своими функциями и WinAPI - тогда да.
Но народ на РВ не пользуется инклюдами, а использует либы.
Соответственно нет никакого "/striponly" и средний проект на РВ по размерам может легко обскакать аналогичный на AutoIt.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
asdf8 сказал(а):
Слегка обманчивое впечатление, если пользоваться только своими функциями и WinAPI - тогда да.
Но народ на РВ не пользуется инклюдами, а использует либы.
Соответственно нет никакого "/striponly" и средний проект на РВ по размерам может легко обскакать аналогичный на AutoIt.

Огорчило.

asdf8, раз ты знаком с PB, то скажи пожалуйста, можно ли на нем состряпать dll'ку, которая будет вызывать AutoIt'овскую callback-функцию - DllCallbackRegister()? Смысл в том, чтобы написать обертку для RegNotifyChangeKeyValue(). Т.е. функция из dll запускает RegNotifyChangeKeyValue() в отдельном потоке, а та в свою очередь сигнализирует в DllCallbackRegister().
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Kalisnik
нет, поток и ядро\проц разные вещи. в одном ядре может быть несколько потоков. но если твой поток грузит все ядро, то система сама создаст новые поток на других свободных ядрах
 

asdf8

Скриптер
Сообщения
564
Репутация
152
Yashied
"знаком с PB" правильно сказано :smile:
WinAPI (тобишь про вызовы функций из сторонних dll), по моему, ты, из присутствующих, знаешь лучше всех.
По моему обратный вызов функций организует ОС в потоке отличном от вызывающего и смысла от такой конструкции может не быть.
А если конкретно по вопросу - я не знаю.
Лучше об этом спросить на форуме РВ.
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Kaster

Выразился как-то я неоднозначно. Я имел в виду обратное: один и тот же поток не может обрабатываться двумя и более ядрами? Т.е. что бы мне задействовать всю вычислительную способность моих четырех ядер CPU, мне в любом случае придется разобрать код на четыре потока? А как это сделать? Разделить код на четыре исполняемых файла и запустить все разом? - это я и в AutoIt могу сделать. Тогда как многопоточность организовать из одного файла (конкретно из DLL-ки)?
 

Yashied

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

AutoItX...

asdf8

Хех, а ведь это реально, вот что у меня получилось:

test.pb

Код:
Structure Callback
	*Proc
	*lParam
EndStructure

Procedure Helper(*Param.Callback)
	Delay(3000)
	CallFunctionFast(*Param\Proc, *Param\lParam)
	ClearStructure(*Param, Callback)
	FreeMemory(*Param)
EndProcedure

ProcedureDLL.l Test(*Proc, *lParam)
	*Param.Callback = AllocateMemory(SizeOf(Callback))
	*Param\Proc = *Proc
	*Param\lParam = *lParam
	If CreateThread(@Helper(), *Param)
		ProcedureReturn 1
	Else
		ProcedureReturn 0
	EndIf
EndProcedure

На всякий случай готовый test.dll (~7 KB)

test.au3

Код:
$Int = False

$hProc = DllCallbackRegister('_MyProc', 'none', 'lparam')
$pProc = DllCallbackGetPtr($hProc)
$tData = DllStructCreate('wchar[260]')
$pData = DllStructGetPtr($tData)
DllStructSetData($tData, 1, 'Привет от PureBasic!')
$hDll = DllOpen(@ScriptDir & '\test.dll')
$Ret = DllCall($hDll, 'bool', 'Test', 'ptr', $pProc, 'ptr', $pData)
If (@error) Or (Not $Ret[0]) Then
	MsgBox(16, '', 'Error!')
	Exit
EndIf

ConsoleWrite('DllCall() успешно выполнена! Ждем 3 сек...' & @CR)

While 1
	If $Int Then
		MsgBox(64, '', $Int)
		ExitLoop
	EndIf
	Sleep(100)
WEnd

DllCallbackFree($hProc)
DllClose($hDll)

Func _MyProc($lParam)
	$Int = DllStructGetData(DllStructCreate('wchar[260]', $lParam), 1)
EndFunc   ;==>_MyProc


Работает!

:blum:

P.S

Ну и синтаксис в PB... Врагу не пожелаешь.

:wacko:

P.S.S

Кому-нибудь еще видна польза от этого?
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Kalisnik
что многопточность, что мультипроцессорность делается вручную. это целая наука, но скажу прямо, твое желание загрузить весь свой процессор это лишь самая первая ступень понимания и ошибочная :smile: нет такой супер проги которая разбросает твою задачу на подзадачи для разных устройств обработки, надо делать это самому.
по поводу AutoIt, искусственно организовать многопоточность в нем можно, но бьюсь об заклад, что ты замучаешься с организацией обмена данными между ними и именно это будет узким местом всей твоей деятельности
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Kalisnik сказал(а):
Тогда как многопоточность организовать из одного файла (конкретно из DLL-ки)?

AutoIt не поддерживает многопоточность. Если прикрутить PB, то вот простой пример:

core.dll

Код:
Procedure Core1(*Param)
	While 1
	Wend
EndProcedure

Procedure Core2(*Param)
	While 1
	Wend
EndProcedure

Procedure Core3(*Param)
	While 1
	Wend
EndProcedure

Procedure Core4(*Param)
	While 1
	Wend
EndProcedure

ProcedureDLL Test()
	CreateThread(@Core1(), 0)
	CreateThread(@Core2(), 0)
	CreateThread(@Core3(), 0)
	CreateThread(@Core4(), 0)
EndProcedure

Код:
$hDll = DllOpen(@ScriptDir & '\core.dll')
DllCall($hDll, 'none', 'Test')
Sleep(30000)
DllClose($hDll)


Запусти .au3 и твой проц загрузится на все 100! Если убрать в PB Core3() и Core4(), то получится 50% (при условии, что у тебя четырехядреный проц). Здесь проблема в грамотном распараллеливании поставленной задачи. Например, для вычисления факториала можно разбить вычисления на 4 части, а затем перемножить их. Или, например, можно состряпать dll'ку для сортировки больших массивов в 4 потока, но здесь будет проблема в передачи этого массива в dll и обратно.

P.S

Автоматически разбить готовый процесс на ядра нельзя.
 

asdf8

Скриптер
Сообщения
564
Репутация
152
Yashied

[?]
Цитата сказал(а):
Не в этом смысле. Хотел, как Мичурин, скрестить скорость РВ с простотой и удобством AutoIt.
Что-то типа:
Код:
Procedure DirCreate (path.s)
   pathMin.s = StringField(path, 1, "\")
   ii=2
   Repeat
      Result$ = StringField(path, ii, "\")
      If Result$
         pathMin = pathMin+"\"+Result$
         If FileSize(pathMin) = -1
            CreateDirectory(pathMin)
         EndIf
      EndIf
      ii=ii+1
   Until Result$=""
   If FileSize(path) = -2
      ProcedureReturn 1
   Else 
      ProcedureReturn 0
   EndIf
EndProcedure

Procedure FileCopy ( source.s, dest.s, flag=0 ) 
   RetVal=0
   Select flag
      Case 0
         If FileSize(dest) < 0
            RetVal=CopyFile(source, dest)
         EndIf
      Case 1
         RetVal=CopyFile(source, dest)
      Case 8
         destDir$ = RTrim(GetPathPart(dest), "\")
         If FileSize(destDir$) = -1
            DirCreate(destDir$)
            RetVal=CopyFile(source, dest)
         Else
            If FileSize(dest) < 0
               RetVal=CopyFile(source, dest)
            EndIf
         EndIf
      Case 9
         destDir$ = RTrim(GetPathPart(dest), "\")
         If FileSize(destDir$) = -1
            DirCreate(destDir$)
            RetVal=CopyFile(source, dest)
         Else
            RetVal=CopyFile(source, dest)
         EndIf
   EndSelect
  ProcedureReturn RetVal
EndProcedure
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Yashied

Весьма доходчиво. А пауза в AutoIt-коде потому что в данном случае этот код не будет "ждать" завершения работы DLL-ки? Значит если указать функцию ProcedureReturn, то код AutoIt приостоновится до выполнения DLL-ки? - так что ли...
Т.е. мне нужно что бы код Autoit "ждал" DLL-ку.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Kalisnik сказал(а):
Т.е. мне нужно что бы код Autoit "ждал" DLL-ку.

Dll не программа, если завершится основной код, то и dll будет выгружена из памяти. Можно и не выходить из dll-функции, а дождаться, пока все потоки отработают, и затем возвратить результат в DllCall(). В этом случае AutoIt код будет приостановлен до завершения всех Core1() - Core4().

Код:
Procedure Core1(*Param)
   While 1
   Wend
EndProcedure

Procedure Core2(*Param)
   While 1
   Wend
EndProcedure

Procedure Core3(*Param)
   While 1
   Wend
EndProcedure

Procedure Core4(*Param)
   While 1
   Wend
EndProcedure

ProcedureDLL Test()
   Thread1 = CreateThread(@Core1(), 0)
   Thread2 = CreateThread(@Core2(), 0)
   Thread3 = CreateThread(@Core3(), 0)
   Thread4 = CreateThread(@Core4(), 0)
   Delay(20000)
   KillThread(Thread1)
   KillThread(Thread2)
   KillThread(Thread3)
   KillThread(Thread4)
EndProcedure

Код:
DllCall(@ScriptDir & '\core.dll', 'none', 'Test')
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Yashied [?]
но здесь будет проблема в передачи этого массива в dll и обратно

А мне какраз нужно массив из DLL'ки в AutoIt передавать. Значит функция ProcedureReturn в PB это не поддерживает? Хмм... Как же передать в AutoIt множество значений?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Kalisnik сказал(а):
Как же передать в AutoIt множество значений?

Только через структуру.

Код:
Dim $aData[1000]
For $i = 0 To 999
	$aData[$i] = Random(0, 65535, 1)
Next

; Создаем и заполняем структуру

$tData = DllStructCreate('word[1000]')
$pData = DllStructGetPtr($tData)
For $i = 1 To 1000
	DllStructSetData($tData, $i, $aData[$i - 1])
Next

; Передаем адрес структуры в функцию MyFunc()
DllCall(@ScriptDir & '\MyDll.dll', 'bool', 'MyFunc', 'ptr', $pData)
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Yashied

Разобрался! Получилось! Чтоб это все прописывать, это надо руки без костей иметь! :laugh: Почему у всех ЯП синтаксис ни такой как в AutoIt... :wall_brake:

П\с: Спасибо! ;) "+1" - не ставится в течении 24-х часов. :angel:
 
Автор
K

Kalisnik

Эволюция
Сообщения
295
Репутация
63
Yashied [?]

Шутите все? :smile:

Пожалуйста:

Код:
Structure Test
  a.w
  b.w
  c.w
  d.w
  e.w
EndStructure

ProcedureDLL.w Test(*pi.Test)
  *pi\a = 34
  *pi\b = 7
  *pi\c = 15
  *pi\d = 28
  *pi\e = 19
EndProcedure

Код:
#include <Array.au3>

Dim $Dll, $Ara[5], $StrukP, $StrukT

$StrukT = DllStructCreate("word[5]")
$StrukP = DllStructGetPtr($StrukT)

$Dll = DllOpen("test.dll")
DllCall($Dll, "bool", "Test", "ptr", $StrukP)
For $i = 0 To 4
	$Ara[$i] = DllStructGetData($StrukT, 1, $i + 1)
Next

_ArrayDisplay($Ara)

DllClose($Dll)


П\с: Синтаксис в PB конечно с заковыркой, но вот сейчас смотрю на код и вроде все совсем не сложно. :smile: Но руки все равно без костей надо иметь!
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Для массива можно написать так:

Код:
Structure Arr
  Value.u[1000]
EndStructure

Procedure Core1(*Param.Arr)
	For i = 0 To 249
		*Param\Value[i] = *Param\Value[i] / 2
	Next
EndProcedure

Procedure Core2(*Param.Arr)
	For i = 250 To 499
		*Param\Value[i] = *Param\Value[i] / 2
	Next
EndProcedure

Procedure Core3(*Param.Arr)
	For i = 500 To 749
		*Param\Value[i] = *Param\Value[i] / 2
	Next
EndProcedure

Procedure Core4(*Param.Arr)
	For i = 750 To 999
		*Param\Value[i] = *Param\Value[i] / 2
	Next
EndProcedure

ProcedureDLL MyFunc(*Param.Arr)
	Thread1 = CreateThread(@Core1(), *Param)
	Thread2 = CreateThread(@Core2(), *Param)
	Thread3 = CreateThread(@Core3(), *Param)
	Thread4 = CreateThread(@Core4(), *Param)
	If (Not Thread1) Or (Not Thread2) Or (Not Thread3) Or (Not Thread4)
		KillThread(Thread1)
		KillThread(Thread2)
		KillThread(Thread3)
		KillThread(Thread4)
		ProcedureReturn 0
	EndIf
	WaitThread(Thread1)
	WaitThread(Thread2)
	WaitThread(Thread3)
	WaitThread(Thread4)
	ProcedureReturn 1
EndProcedure

Код:
#Include <Array.au3>

Dim $aData[1000]

For $i = 0 To 999
    $aData[$i] = Random(0, 65535, 1)
Next

_ArrayDisplay($aData)

$tData = DllStructCreate('word[1000]')
$pData = DllStructGetPtr($tData)
For $i = 1 To 1000
    DllStructSetData($tData, 1, $aData[$i - 1], $i)
Next
$aResult = DllCall(@ScriptDir & '\MyDll.dll', 'bool', 'MyFunc', 'ptr', $pData)
If (@error) Or (Not $aResult[0]) Then
	MsgBox(16, '', 'Error!')
	Exit
EndIf

For $i = 1 To 1000
    $aData[$i - 1] = DllStructGetData($tData, 1, $i)
Next

_ArrayDisplay($aData)


Правда не знаю, на сколько это распараллелится...
 
Верх