Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   AutoIt (http://forum.oszone.net/forumdisplay.php?f=103)
-   -   [решено] как поставить скрипт в очередь ? (http://forum.oszone.net/showthread.php?t=225370)

mitiya 16-01-2012 12:20 1836990

как поставить скрипт в очередь ?
 
есть у меня скрипт на autoit который может быть запущен несколько раз в то время пока первый еще не успел отработать до конца. И мне нужно что бы они как бы в очередь вставали. Работать параллельно им нельзя и сбрасывать те что запущены тоже нельзя.
Есть способ _Singleton() что бы узнать, что уже запущен скрипт, если бы можно было только 2 экземпляра запустить то я бы просто проверку в цикл поставил, но когда их может быть несколько все становится сложнее.
Нужно знать длину очереди и номер в очереди, тут я малость встал.
Может есть какие идеи ?

Iska 16-01-2012 14:10 1837063

Можно воспользоваться тем, что PID'ы растут последовательно.

При запуске приложения проверяйте наличие процессов с тем же именем (исключая, естественно, сам текущий экземпляр приложения), получите их PID'ы, следите за процессом с наивысшим PID'ом, и ждите, пока он не будет завершён.

Creat0R 16-01-2012 17:14 1837180

Цитата:

Цитата Iska
Можно воспользоваться тем, что PID'ы растут последовательно. »

Вообще то нет, есть у меня в процессах старые процессы с меньшим большим значением у PID.

Iska 16-01-2012 17:33 1837194

Цитата:

Цитата Creat0R
с меньшим значением у PID. »

С большим, наверное?

Я не находил информацию, как подтверждающую, либо опровергающую ранее приведённое предположение. Буду рад, ежели кто поделится.

ferget 16-01-2012 18:39 1837248

проверяю

запускаю калькулятор PID 2148, затем блокнот PID 5120

закрываю калькулятор и блокнот

снова запускаю

калькулятор PID 5632, затем блокнот PID 2296

а самый высокий PID у pythonw.exe 6140, а запущен он еще утром

так что по PID не отследить

Creat0R 16-01-2012 21:11 1837383

В общем вот что у меня получилось:

Код:

$iQueue_Position = _AppSetQueue(500)
MsgBox(64, 'Title', StringFormat('Process: %i\nQueue position: %i', @AutoItPID, $iQueue_Position))

; #FUNCTION# ====================================================================================================
; Name...........: _AppSetQueue
; Description....: Sets Queue for the next instances of this script.
; Syntax.........: _AppSetQueue($iWait = 500, $iOnStart = 1)
; Parameters.....: $iWait [Optional] - Wait between each queue check (default is 500 ms).
;                  $iOnStart [Optional/Internal] - Indicates if the function was executed on start, only internal usage.
;
;
; Return values..: Success - Return Queue position (-1 if this is the first instance of the program).
;                  Failure - None.
; Author.........:    G.Sandler (CreatoR)
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _AppSetQueue($iWait = 500, $iOnStart = 1)
    Local $sUnique_Win, $sQueue, $aQueue, $iC, $sTmp_Script, $nEdit, $hFile, $iLast_Queue

    $sUnique_Win = "__Au3_Queue_Window__"
    $sQueue = ControlGetText($sUnique_Win, "", "Edit1")
    $aQueue = StringSplit($sQueue, @CRLF, 1)

    ;The script Exits (called by OnAutoItExitRegister)
    If Not IsDeclared("iOnStart") Then
        $sQueue = ""
        $iC = 0

        For $i = 1 To $aQueue[0]
            If Not StringRegExp($aQueue[$i], '^\d+:' & @AutoItPID) Then
                $iC += 1
                $sQueue &= $iC & ":" & StringRegExpReplace($aQueue[$i], '^\d+:', '') & @CRLF
            EndIf
        Next

        $sQueue = StringStripWS($sQueue, 3)
        ControlSetText($sUnique_Win, "", "Edit1", $sQueue)
        Return
    EndIf

    OnAutoItExitRegister("_AppSetQueue")

    If Not WinExists($sUnique_Win) Then
        $sTmp_Script = _
            '#NoTrayIcon' & @CRLF & _
            'GUICreate("' & $sUnique_Win & '", 100, 20)' & @CRLF & _
            '$nEdit = GUICtrlCreateEdit("1:' & @AutoItPID & '", 0, 0, 100, 20)' & @CRLF & @CRLF & _
            'While GUICtrlRead($nEdit) <> ""' & @CRLF & _
            '    Sleep(100)' & @CRLF & _
            'WEnd' & @CRLF & @CRLF & _
            'FileDelete(@TempDir & "\~tmp_GUI_src.tmp")' & @CRLF & _
            'Run(@ComSpec & '' /C Del /F /Q "'' & @TempDir & ''\~tmp_GUI.tmp"'', '''', @SW_HIDE)' & @CRLF & _
            'Exit' & @CRLF

        $hFile = FileOpen(@TempDir & "\~tmp_GUI_src.tmp", 2)
        FileWrite($hFile, $sTmp_Script)
        FileClose($hFile)

        FileCopy(@AutoItExe, @TempDir & "\~tmp_GUI.tmp", 1)
        Run(@TempDir & '\~tmp_GUI.tmp /AutoIt3ExecuteScript "' & @TempDir & '\~tmp_GUI_src.tmp"')

        Return -1
    EndIf

    $iLast_Queue = Number(StringRegExpReplace($aQueue[$aQueue[0]], '^(\d+)', '\1'))
    $sQueue &= @CRLF & $iLast_Queue + 1 & ":" & @AutoItPID
    ControlSetText($sUnique_Win, "", "Edit1", $sQueue)

    While 1
        $sQueue = ControlGetText($sUnique_Win, "", "Edit1")
        $aQueue = StringSplit($sQueue, @CRLF, 1)

        If StringRegExp($aQueue[1], '^\d+:' & @AutoItPID) Then
            Return $aQueue[0] ;It' our turn in the queue
        EndIf

        Sleep($iWait)
    WEnd
EndFunc


mitiya 17-01-2012 01:59 1837558

упс, не обновил страницу. а тут уже кучу всего написали ))

я так понимаю тут временные файлы используются ?
мне приходила в голову идея с файлами, но не хотелось мучить ssd и я на эту идею подзабил.

Creat0R 17-01-2012 02:08 1837560

Цитата:

Цитата mitiya
я так понимаю тут временные файлы используются ? »

Используется, и только один раз при запуске первой копии программы.
Делается это для того, чтобы запустить дополнительный (промежуточный-нейтральный) скрипт, который действует как хранилище для очереди запускаемых копий скриптов.

mitiya 17-01-2012 02:15 1837562

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

Creat0R 17-01-2012 03:20 1837576

Цитата:

Цитата mitiya
как там все работает »

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

Цитата:

Цитата mitiya
код сложноват для меня »

А всё что от вас требуется, так это помещение этого кода в начало вашего скрипта.
Там где MsgBox, это и есть тело вашего скрипта.

Немного подправил код.

Creat0R 17-01-2012 04:50 1837587

Вот более простой скрипт (не использует временных файлов):

Код:

$iQueue_Position = _AppSetQueue(100)
MsgBox(64, 'Title', StringFormat('Process: %i\nQueue position: %i', @AutoItPID, $iQueue_Position))

; #FUNCTION# ====================================================================================================
; Name...........: _AppSetQueue
; Description....: Sets Queue for the next instances of this script.
; Syntax.........: _AppSetQueue($iWait = 100)
; Parameters.....: $iWait [Optional] - Waiting queue (default is 500 ms).
;
;
; Return values..: Success - Return Queue position (0 if this is the first instance of the program).
;                  Failure - None.
; Author.........: G.Sandler (CreatoR)
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _AppSetQueue($iWait = 100)
    Local $sUnique_Win, $sScriptName, $aProcList, $aWinList, $iQueue, $hPrev_Queue_Win, $j

    $sUnique_Win = "_Au3_Queue_Window_"
    $sScriptName = @ScriptName

    If Not @Compiled Then
        $sScriptName = StringRegExpReplace(@AutoItExe, '^.*\\', '')
    EndIf

    $aProcList = ProcessList($sScriptName)
    $aWinList = WinList($sUnique_Win)

    $iQueue = 0
    $hPrev_Queue_Win = 0

    If UBound($aWinList) > 1 Then
        $hPrev_Queue_Win = $aWinList[1][1]
    EndIf

    For $i = 1 To UBound($aProcList)-1
        For $j = 1 To UBound($aWinList)-1
            If $aWinList[$j][0] = $sUnique_Win And WinGetProcess($aWinList[$j][1]) = $aProcList[$i][1] Then
                $iQueue += 1

                If $j > 1 Then
                    $hPrev_Queue_Win = $aWinList[$j-1][1]
                EndIf

                ExitLoop
            EndIf
        Next
    Next

    AutoItWinSetTitle($sUnique_Win & "__")
    ControlSetText($sUnique_Win & "__", "", "Edit1", $iQueue + 1)
    AutoItWinSetTitle($sUnique_Win)

    If $iQueue = 0 Then
        Return 0
    EndIf

    While WinExists($hPrev_Queue_Win)
        Sleep($iWait)
    WEnd

    Return $iQueue
EndFunc


mitiya 17-01-2012 12:42 1837806

был бы признателен за объяснение что тут и как .

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

Creat0R 17-01-2012 13:22 1837836

Цитата:

Цитата mitiya
был бы признателен за объяснение что тут и как »

Я использовал „систему билетов“, как это сделано например в поликлинике :)

Каждый запущенный скрипт получает „билетик“, для этого используется встроенное окно AutoIt (см. AutoItWinGetTitle).
Далее проверяются все окна от процессов нашего скрипта, и если скрипт на очереди (первый в списке), то продолжается (выполняется) его работа.

Цитата:

Цитата mitiya
Если бы можно было это делать, то можно было бы хранить номер в очереди у каждого процесса. »

Спрашивается зачем?

Пример выше разве не работает?

mitiya 17-01-2012 13:40 1837849

ну у меня скрипт без окон.
и самое главное они запускаются на терминальном сервере, и в результате скрпты всех пользователей в очередь встают, а надо чтоб очередь создавалась у каждого пользователя своя. с помощью _Singleton() легко отслеживается процесс от текущего пользователя, если делать к примеру так _Singleton($sProIDText & @UserName, 1)

Creat0R 17-01-2012 22:52 1838432

Цитата:

Цитата mitiya
у меня скрипт без окон »

У AutoIt есть встроенное (скрытое) окно, его и использует моя функция.

Цитата:

Цитата mitiya
самое главное они запускаются на терминальном сервере, и в результате скрпты всех пользователей в очередь встают, а надо чтоб очередь создавалась у каждого пользователя своя »

Вот это «самое главное» следует указывать в самом начале, при созданий темы.

Можно попробовать так:

Код:

#include "WinAPIEx.au3" ;http://autoit-script.ru/index.php/topic,47.0.html

$iQueue_Position = _AppSetQueue(100)
MsgBox(64, 'Title', StringFormat('Process: %i\nQueue position: %i', @AutoItPID, $iQueue_Position))

; #FUNCTION# ====================================================================================================
; Name...........: _AppSetQueue
; Description....: Sets Queue for the next instances of this script.
; Syntax.........: _AppSetQueue($iWait = 100, $sUserName = @UserName)
; Parameters.....: $iWait [Optional] - Waiting queue (default is 100 ms).
;                  $sUserName [Optional] - Limit queue for specfific system user.
;
;
; Return values..: Success - Return Queue position (0 if this is the first instance of the program).
;                  Failure - None.
;
; Author.........: G.Sandler (CreatoR)
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _AppSetQueue($iWait = 100, $sUserName = @UserName)
    Local $sUnique_Win, $sScriptName, $aProcList, $aWinList, $iQueue, $hPrev_Queue_Win, $aProcUser

    $sUnique_Win = "_Au3_Queue_Window_"
    $sScriptName = @ScriptName

    If Not @Compiled Then
        $sScriptName = StringRegExpReplace(@AutoItExe, '^.*\\', '')
    EndIf

    $aProcList = ProcessList($sScriptName)
    $aWinList = WinList($sUnique_Win)

    $iQueue = 0
    $hPrev_Queue_Win = 0

    If UBound($aWinList) > 1 Then
        $hPrev_Queue_Win = $aWinList[1][1]
    EndIf

    For $i = 1 To UBound($aProcList)-1
        $aProcUser = _WinAPI_GetProcessUser($aProcList[$i][1])

        If $aProcUser[0] <> $sUserName Then
            ContinueLoop
        EndIf

        For $j = 1 To UBound($aWinList)-1
            If $aWinList[$j][0] = $sUnique_Win And WinGetProcess($aWinList[$j][1]) = $aProcList[$i][1] Then
                $iQueue += 1

                If $j > 1 Then
                    $hPrev_Queue_Win = $aWinList[$j-1][1]
                EndIf

                ExitLoop
            EndIf
        Next
    Next

    AutoItWinSetTitle($sUnique_Win & "__")
    ControlSetText($sUnique_Win & "__", "", "Edit1", $iQueue + 1)
    AutoItWinSetTitle($sUnique_Win)

    If $iQueue = 0 Then
        Return 0
    EndIf

    While WinExists($hPrev_Queue_Win)
        Sleep($iWait)
    WEnd

    Return $iQueue
EndFunc

нужно подключить библиотеку WinAPIEx.au3.

mitiya 18-01-2012 08:50 1838588

Цитата:

Цитата Creat0R
Вот это «самое главное» следует указывать в самом начале, при созданий темы. »

сам это упусти вначале :)

спасибо

Iska 18-01-2012 10:40 1838653

И я поправил.


Время: 13:00.

Время: 13:00.
© OSzone.net 2001-