У кого-нибудь есть опыт его применения? Какие впечатления? Хотелось бы узнать мнение гуру.
#NoTrayIcon
#include 'N.au3'
global $Counter = 0
func task()
MsgBox(0, '', $Counter)
endfunc
func main()
$Counter += 1
local $t = NRun('task')
NWait($t)
endfunc
NMain('main')
Т.е. по факту оно не работает? И применять его пусть даже для квазимультипоточности нельзя?в окошке должно быть число 1, но будет 0
Оно непонятно как работает.оно не работает?
То есть он предлагает изучать исходник dll чтобы это понять.How it works?
Please see the C++ source code, I'll update soon
Собственно, первоначально у меня в этом и был вопрос. Можно ли это сделать средствами AutoIt?Если кратко, exe файл считывается в память
это сюр.Нет там многопоточности что не удивительно. Потоки запускаются в контексте процесса и они делят между собой его виртуальное адресное пространство. То есть переменные общие и если запустить этот кодв окошке должно быть число 1, но будет 0.Код:#NoTrayIcon #include 'N.au3' global $Counter = 0 func task() MsgBox(0, '', $Counter) endfunc func main() $Counter += 1 local $t = NRun('task') NWait($t) endfunc NMain('main')
global $g = NGlobal()
local $state = NLocal()
; Run task with state.
NRun('task', $state)
$state.ready = true
; task
func task($state)
while true
; Change GUI title when ready.
if $state.ready then
#NoTrayIcon ; Should add this to prevent tray icon in sub-thread.
#include 'N.au3'
; This test create a new thread worker that changes GUI title randomly.
; task1
func task1($state)
local $gui = HWnd($state.hwnd)
while true
if $state.ready then
local $n = Random(0xFF, 0xFFFFFF, 1)
WinSetTitle($gui, '', 'Random: ' & $n)
ControlSetText($gui, "", $state.label1, $state.first)
$state.first += 1
endif
Sleep(20)
wend
endfunc
; task2
func task2($state)
local $gui = HWnd($state.hwnd) ; .hwnd is casted to int, just convert it to HWND
while true
if $state.ready then
ControlSetText($gui, "", $state.label2, $state.second)
$state.second += 1
endif
Sleep(20)
wend
endfunc
; main
func main()
; Create GUI with 3 buttons.
local $gui = GUICreate('Test 3', 320, 150)
local $l1 = GUICtrlCreateLabel("label1", 10, 30)
local $l2 = GUICtrlCreateLabel("label2", 70, 30)
local $btn = GUICtrlCreateButton('Start', 20, 60, 80, 30)
GUISetState(@SW_SHOW)
; Create shared state.
local $state = NLocal()
$state.hwnd = $gui ; GUI handle
$state.ready = false ; ready state
$state.first = 1
$state.second = 1
$state.label1 = $l1
$state.label2 = $l2
; Run task with state.
NRun('task1', $state)
NRun('task2', $state)
; GUI message loop.
while true
switch GUIGetMsg()
; close
case -3
exit
; button 1
case $btn
if $state.ready then
$state.ready = false
GUICtrlSetData($btn, 'Start')
else
$state.ready = true
GUICtrlSetData($btn, 'Stop')
endif
endswitch
wend
endfunc
; Execute main entry.
NMain('main')
Не путайте процессы и потоки. У потоков в пределах процесса общее виртуальное адресное пространство.вы вообще что-нибудь читали, о том как работают потоки?
и что такое области видимости?
нельзя просто так взять, и передать одну переменную с
одного потока в другой!
Все переменные общие для потоков в процессе.Создает поток для выполнения в виртуальном адресном пространстве вызывающего процесса.
Это разруливается мьютексами / критическими секциями.+ если будет одновременное обращение к одной и той-же
переменной с разных потоков, приложение может упасть,
это к вопросу о синхронизаци.
Пример это замечательно, но где документация? Она нужна чтобы понять как использовать те или иные средства.вот из примера 1:
глобальная переменная
Это не "True Multi-threading", а немного другое.3 независимых цикла While !! как это нету многопоточности?!
это не "thread-safe" практика.Все переменные общие для потоков в процессе.
Поэтому вы не правы. Переменные изначально доступны во всех потоках процесса без всякий ухищрений.
Я выше писал, при необходимости доступа потоков к общим ресурсам используют мьютекс.это не "thread-safe" практика.
Несколько функций из dll."новый экземпляр exe файла запускаемый из памяти"
там не новый ехе запускается каждый раз из памяти, там ехе читается 1 раз в память,
а потом везде используется AutoItObject.
static void CALLBACK N_ThreadRoutine(Thread *thread)
{
// Execute main entry point.
WinMain_t main = (WinMain_t)N_MemoryModuleGetEntryPoint(thread->module);
main(GetModuleHandleA(NULL), NULL, GetCommandLineW(), 0);
}
DWORD WINAPI NAPI_Run(LPCSTR fn, LPDISPATCH local)
{
DWORD id;
Thread *thread = new Thread();
// Load current EXE with MemoryModule.
SIZE_T moduleSize;
LPVOID moduleData = N_GetBinaryModule(&moduleSize);
thread->module = MemoryLoadLibrary(moduleData, moduleSize);
// Save thread's function name.
lstrcpyA(thread->func, fn);
// Save local shared.
thread->local = local;
// Create suspended thread.
thread->handle = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)&N_ThreadRoutine, (LPVOID)thread, CREATE_SUSPENDED, &id);
// Add local object ref.
if (local != NULL)
local->AddRef();
// Insert to map and resume it.
g_threadMap[id] = thread;
ResumeThread(thread->handle);
return id;
}
Я так и поступаю.берите уже сразу язык в котором предусмотрено "мультичтовамнужно" и делайте на нем.
Такая в которой написано как правильно пользоваться этой библиотекой.какая документация?
Процы давно не одноядерные.можете прочитать у майкрософта за потоки и задачи, там сказано, что потоки даже если их и много,
все-равно будут выполнятся синхронно, это просто процессор будет переключатся между потоками,
тем самым, ваше приложение будет выполнятся медленно.
#NoTrayIcon
#include 'N.au3'
global const $Count=2 ; Число потоков
global $g = NGlobal()
func task($p)
ConsoleWrite($p.num&@CRLF)
while $p.break = false
$g.aTask($p.num) += 1
wend
endfunc
func main()
dim $t[$Count]
dim $p[$Count]
for $i=0 to $Count-1
$g.aTask($i)=0
$p[$i] = NLocal()
$p[$i].break = false
$p[$i].num = $i
$t[$i] = NRun('task', $p[$i])
next
Sleep(1000)
for $i=0 to $Count-1
$p[$i].break = true
next
NWaitAll()
ConsoleWrite(@crlf)
Local $All = 0
for $i=0 to $Count-1
ConsoleWrite($g.aTask($i)&@crlf)
$All += $g.aTask($i)
next
ConsoleWrite("All="&$All&@CRLF)
endfunc
NMain('main')
#NoTrayIcon
global $g[1], $Br=false
func task()
while $Br = false
$g[0] += 1
wend
endfunc
Func BreakLoop()
$Br=True
EndFunc
AdlibRegister("BreakLoop", 1000)
task()
ConsoleWrite($g[0]&@CRLF)
#NoTrayIcon
#include 'N.au3'
global $g = NGlobal()
func task($g)
Local $hTimer = TimerInit()
local $b = 0
For $i = 0 To 100000 Step 1
$b += 1
Next
$g.res = TimerDiff($hTimer)
endfunc
func main()
$g.res = 0
NRun('task', $g)
While true
If $g.res > 0 Then
ConsoleWrite($g.res & @CRLF)
ExitLoop
endif
wend
endfunc
NMain('main')
#NoTrayIcon
func task()
Local $hTimer = TimerInit()
local $b = 0
For $i = 0 To 100000 Step 1
$b += 1
Next
$g = TimerDiff($hTimer)
ConsoleWrite($g & @CRLF)
endfunc
task()
За 10 миллисекунд выполняет.2.au3 = 64.6865862090028
#NoTrayIcon
#include 'N.au3'
global $g = NGlobal()
func task($g)
Local $hTimer = TimerInit()
local $b = 0
For $i = 0 To 100000 Step 1
$b += 1
Next
$g.res = TimerDiff($hTimer)
endfunc
func task2($g)
Local $hTimer = TimerInit()
local $b2 = 0
For $i2 = 0 To 100000 Step 1
$b2 += 1
Next
$g.res2 = TimerDiff($hTimer)
endfunc
func main()
$g.res = 0
$g.res2 = 0
NRun('task', $g)
NRun('task2', $g)
While true
If $g.res > 0 And $g.res2 > 0 Then
ConsoleWrite($g.res & @CRLF)
ConsoleWrite($g.res2 & @CRLF)
ExitLoop
endif
wend
endfunc
NMain('main')